On Fri, Oct 19, 2018 at 3:43 PM Bernhard Reutner-Fischer
<rep.dot....@gmail.com> wrote:
> On Fri, 19 Oct 2018 at 15:30, Bernhard Reutner-Fischer
> <rep.dot....@gmail.com> wrote:
> > On Fri, 19 Oct 2018 at 11:03, Cristian Ionescu-Idbohrn
> > <cristian.ionescu-idbo...@axis.com> wrote:
>
> Oh, an I should mention that on a 64bit box we diverge from coreutils printf:
>
> $ printf "%f\n" '  +18446744073709551614'
> 18446744073709551614.000000
> $ ./busybox printf "%f\n" '  +18446744073709551614'
> 18446744073709551616.000000

It's far worse than that:

$ ./busybox printf "%f\n" 18446744073709550592 18446744073709553665
18446744073709551616.000000
18446744073709551616.000000

64-bit double's mantissa is only 53 bits...

With "long double" shenanigans, I managed to "improve" this to:

$ ./busybox printf "%f\n" 18446744073709550592 18446744073709553665
18446744073709550591.500000
18446744073709553663.500000

at this cost:

function                                             old     new   delta
printf_main                                          909     976     +67
strtold                                                -      19     +19
print_direc                                          457     475     +18
conv_strtod                                           54      61      +7
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 3/0 up/down: 130/0)             Total: 111 bytes

See attached. Do you think it's worth it?
diff --git a/coreutils/printf.c b/coreutils/printf.c
index 67d3b2eda..215f4fef9 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -120,12 +120,18 @@ static void FAST_FUNC conv_strtoll(const char *arg, void *result)
 static void FAST_FUNC conv_strtod(const char *arg, void *result)
 {
 	char *end;
-	/* Well, this one allows leading whitespace... so what? */
-	/* What I like much less is that "-" accepted too! :( */
-	*(double*)result = strtod(arg, &end);
+
+	/* If long double is no different than double, avoid using strtold() */
+	if (sizeof(double) == sizeof(long double))
+		/* Well, this one allows leading whitespace... so what? */
+		/* What I like much less is that "-" accepted too! :( */
+		*(long double*)result = strtod(arg, &end);
+	else
+		*(long double*)result = strtold(arg, &end);
+
 	if (end[0]) {
 		errno = ERANGE;
-		*(double*)result = 0;
+		*(long double*)result = 0;
 	}
 }
 
@@ -144,9 +150,9 @@ static long long my_xstrtoll(const char *arg)
 		result = 0;
 	return result;
 }
-static double my_xstrtod(const char *arg)
+static long double my_xstrtod(const char *arg)
 {
-	double result;
+	long double result;
 	multiconvert(arg, &result, conv_strtod);
 	return result;
 }
@@ -187,7 +193,6 @@ static void print_direc(char *format, unsigned fmt_length,
 		const char *argument)
 {
 	long long llv;
-	double dv;
 	char saved;
 	char *have_prec, *have_width;
 
@@ -255,17 +260,35 @@ static void print_direc(char *format, unsigned fmt_length,
 	case 'E':
 	case 'g':
 	case 'G':
-		dv = my_xstrtod(argument);
-		if (!have_width) {
-			if (!have_prec)
-				printf(format, dv);
-			else
-				printf(format, precision, dv);
+		if (sizeof(double) == sizeof(long double)) {
+			double dv;
+			dv = my_xstrtod(argument);
+			if (!have_width) {
+				if (!have_prec)
+					printf(format, dv);
+				else
+					printf(format, precision, dv);
+			} else {
+				if (!have_prec)
+					printf(format, field_width, dv);
+				else
+					printf(format, field_width, precision, dv);
+			}
 		} else {
-			if (!have_prec)
-				printf(format, field_width, dv);
-			else
-				printf(format, field_width, precision, dv);
+			/* Parsing code added "L" prefix (a-la "%Lf") */
+			long double dv;
+			dv = my_xstrtod(argument);
+			if (!have_width) {
+				if (!have_prec)
+					printf(format, dv);
+				else
+					printf(format, precision, dv);
+			} else {
+				if (!have_prec)
+					printf(format, field_width, dv);
+				else
+					printf(format, field_width, precision, dv);
+			}
 		}
 		break;
 	} /* switch */
@@ -371,6 +394,18 @@ static char **print_formatted(char *f, char **argv, int *conv_err)
 					//bb_error_msg("<%s>", p);
 					direc_length += 2;
 					direc_start = p;
+				} else
+				if (sizeof(double) < sizeof(long double)
+				 && p - format_chars <= 10
+				) {
+					/* it is one of "feEgG" */
+					p = xmalloc(direc_length + 2);
+					memcpy(p, direc_start, direc_length);
+					p[direc_length] = p[direc_length - 1];
+					p[direc_length - 1] = 'L';
+					//bb_error_msg("<%s>", p);
+					direc_length += 1;
+					direc_start = p;
 				} else {
 					p = NULL;
 				}
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to