for what it's worth, I have these 3 functions in my personal library to, one each for
- Truncated (BAU
awk
approach),
- Floored, and
- Euclidean division
The 3 functions are cross-dependent so to avoid re-inventing the wheel 3 times. Inputs can be in any format - integer, floating point, or numeric strings.
Both dividend and divisor are pre-truncated before any division occurs.
With gawk -M
(bigint via GMP
), these functions offer UNLIMITED division precision without needing to set the PREC
parameter. Without GMP
, precision offered is the standard 53-bits of double precision FP underlying all of awk
.
function divmod_trunc(___, _, __) {
return \
(__ = _ = int(_)) == (_ = !!_) \
? (+(__ = "=%_/=") < _ \
? ((!_)__) ___ \
: ERRNO = (_ = "NAN")__ (! (___ = +int(substr(___,
_ = (__ = _)^(_ < _), -(_++) + _^_^_) ".")) \
? __ : substr("-INF", _ - (___ < !_)))) \
: (_ = (___ = \
int(___)) % __) "=%_/=" (___ - _) /__
}
function divmod_floor(__, _, ___) {
return \
((__ = int(__)) < !!__) == ((_ = int(_)) < !!_) || !_ \
? divmod_trunc(__, _) \
: (__ - _ * (___ = (\
__ - (___ = __ % _)) / _ - !!_)) ("=%_/=")___
}
function divmod_euclid(__, _, ___) {
return \
(___ = (_ = int(_)) == !!_ ||
-(__ = int(__)) < __) || __*_ < !_ \
? (___ ? divmod_trunc(__, _) \
: divmod_floor(__, _)) \
: ((___ = (__ - (\
__ %= _)) / _)^!_ * __ - _) "=%_/=" (++___)
}
Since awk
lack tuples as a return type, these functions attempt to emulate that effect by simultaneously returning both remainder and quotient as a "string-connected tuple", in the format
REMAINDER=%_/=QUOTIENT
All zeros are treated as unsigned. Division by zero return unsigned NAN
as the remainder, and one of NAN
, INF
, or -INF
as its quotient.
This pair of primes will showcase their differences :
468888899996789 / 23456789
TRUNC :: 2701014=%_/=19989475
FLOOR :: 2701014=%_/=19989475
ECLID :: 2701014=%_/=19989475
-468888899996789 / 23456789
TRUNC :: -2701014=%_/=-19989475
FLOOR :: 20755775=%_/=-19989476
ECLID :: 20755775=%_/=-19989476
468888899996789 / -23456789
TRUNC :: 2701014=%_/=-19989475
FLOOR :: -20755775=%_/=-19989476
ECLID :: 2701014=%_/=-19989475
-468888899996789 / -23456789
TRUNC :: -2701014=%_/=19989475
FLOOR :: -2701014=%_/=19989475
ECLID :: 20755775=%_/=19989476
These functions are fully POSIX
-compliant and works on all awk
s. No numbers are hard-coded at all in these functions since all numeric constants and offsets required by the functions are generated on the fly as part of input cleansing.