1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-18 07:13:36 +02:00

rearrange scan_scaled(3) ordering of multiplications and divisions

to better preserve accuracy for large exponents. From metsw24-max
via https://github.com/openssh/openssh-portable/pull/671/

ok tb@
This commit is contained in:
djm
2026-06-06 23:49:25 +00:00
parent f28d8ad5e1
commit a99ed17cfa
+28 -12
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: fmt_scaled.c,v 1.23 2022/12/27 17:10:08 jmc Exp $ */
/* $OpenBSD: fmt_scaled.c,v 1.24 2026/06/06 23:49:25 djm Exp $ */
/*
* Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
@@ -73,7 +73,7 @@ scan_scaled(char *scaled, long long *result)
{
char *p = scaled;
int sign = 0;
unsigned int i, ndigits = 0, fract_digits = 0;
unsigned int i, ndigits = 0, fract_digits = 0, muls = 0, divs = 0;
long long scale_fact = 1, whole = 0, fpart = 0;
/* Skip leading whitespace */
@@ -182,17 +182,33 @@ scan_scaled(char *scaled, long long *result)
/* scale whole part */
whole *= scale_fact;
/* truncate fpart so it doesn't overflow.
* then scale fractional part.
*/
while (fpart >= LLONG_MAX / scale_fact) {
fpart /= 10;
fract_digits--;
}
fpart *= scale_fact;
if (fract_digits > 0) {
for (i = 0; i < fract_digits -1; i++)
/*
* Scale fractional part: compute
* fpart * scale_fact / 10^(fract_digits-1)
* without intermediate overflow. scale_fact is 1024^i,
* i.e. a power of 1024 = 2^10. Interleave
* multiply-by-1024 with divide-by-10 so the running
* value stays within long long range while preserving
* precision.
*/
muls = i;
divs = fract_digits > 0 ? fract_digits - 1 : 0;
while (muls > 0 && divs > 0) {
if (fpart <= LLONG_MAX / 1024) {
fpart *= 1024;
muls--;
} else {
fpart /= 10;
divs--;
}
}
while (muls > 0) {
fpart *= 1024;
muls--;
}
while (divs > 0) {
fpart /= 10;
divs--;
}
if (sign == -1)
whole -= fpart;