dc: Don't use negative numbers in divscale() - sbase - suckless unix tools
HTML git clone git://git.suckless.org/sbase
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
DIR commit b7e30e59700d9af15a83ce9dc06a05b4f7926332
DIR parent a2940adeba5293032f6ceb7d218dc9f09d6de984
HTML 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:
M dc.c | 28 +++++++++++++++++++++++++++-
A tests/0049-dc.sh | 16 ++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
---
DIR 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;
}
DIR 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