sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

commit b7e30e59700d9af15a83ce9dc06a05b4f7926332
parent a2940adeba5293032f6ceb7d218dc9f09d6de984
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date:   Tue, 20 Jan 2026 16:00:33 +0100

dc: Don't use negative numbers in divscale()

Divscale uses the function muln() that is not prepared to handle
negative numbers. The solution is to convert them to positive
numbers and handle the sign in divnum() and modnum(). We don't
need a copy of the parameters because they are used directly
with values from the stack, or from the expnum() function that
discards the input parameters when it calls divnum().

Diffstat:
Mdc.c | 28+++++++++++++++++++++++++++-
Atests/0049-dc.sh | 16++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/dc.c b/dc.c @@ -876,16 +876,39 @@ divscale(Num *divd, Num *divr) static Num * divnum(Num *a, Num *b) { + Num *r; + int siga, sigb; + + siga = negative(a); + if (siga) + chsign(a); + + sigb = negative(b); + if (sigb) + chsign(b); + if (!divscale(a, b)) return copy(&zero); - return divmod(a, b, NULL); + r = divmod(a, b, NULL); + if (siga ^ sigb) + chsign(r); + return r; } static Num * modnum(Num *a, Num *b) { Num *mod, *c; + int siga, sigb; + + siga = negative(a); + if (siga) + chsign(a); + + sigb = negative(b); + if (sigb) + chsign(b); if (!divscale(a, b)) return copy(&zero); @@ -893,6 +916,9 @@ modnum(Num *a, Num *b) c = divmod(a, b, &mod); freenum(c); + if (siga) + chsign(mod); + return mod; } diff --git a/tests/0049-dc.sh b/tests/0049-dc.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +tmp=$$.tmp + +trap 'rm -f $tmp' EXIT +trap 'exit $?' HUP INT TERM + +cat <<'EOF' > $tmp +-.2840790438404122960275 +EOF + +$EXEC ../dc <<'EOF' | diff -u - $tmp +22k +_.1755705045849462583368 +.618033988749894848204/p +EOF