Support "%x" etc. formats on more floats

* doc/lispref/strings.texi (Formatting Strings): Document this.
* src/editfns.c (styled_format): Support %o, %x, and %X on
finite floats less than zero or greater than UINTMAX_MAX.
* test/src/editfns-tests.el (format-%x-large-float)
(read-large-integer, format-%o-negative-float):
Adjust tests to match extended behavior.
Rename the latter test from format-%o-invalid-float,
since the float is no longer invalid.

* test/src/editfns-tests.el (format-%x-large-float)
(read-large-integer): Test this.
This commit is contained in:
Paul Eggert 2019-07-23 01:42:32 -07:00
parent 56a3e4a5d3
commit dfb0ba79b5
3 changed files with 27 additions and 21 deletions

View file

@ -923,9 +923,8 @@ Functions}). Thus, strings are enclosed in @samp{"} characters, and
@cindex integer to octal
Replace the specification with the base-eight representation of an
integer. Negative integers are formatted in a platform-dependent
way. The object can also be a nonnegative floating-point
number that is formatted as an integer, dropping any fraction, if the
integer does not exceed machine limits.
way. The object can also be a floating-point number that is formatted
as an integer, dropping any fraction.
@item %d
Replace the specification with the base-ten representation of a signed
@ -938,9 +937,8 @@ formatted as an integer, dropping any fraction.
Replace the specification with the base-sixteen representation of an
integer. Negative integers are formatted in a platform-dependent
way. @samp{%x} uses lower case and @samp{%X} uses upper
case. The object can also be a nonnegative floating-point number that
is formatted as an integer, dropping any fraction, if the integer does
not exceed machine limits.
case. The object can also be a floating-point number that is
formatted as an integer, dropping any fraction.
@item %c
Replace the specification with the character which is the value given.

View file

@ -3594,6 +3594,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
sprintf_bytes = prec != 0;
}
else if (BIGNUMP (arg))
bignum_arg:
{
int base = ((conversion == 'd' || conversion == 'i') ? 10
: conversion == 'o' ? 8 : 16);
@ -3655,11 +3656,17 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
else
{
double d = XFLOAT_DATA (arg);
double uintmax = UINTMAX_MAX;
if (! (0 <= d && d < uintmax + 1))
xsignal1 (Qoverflow_error, arg);
x = d;
negative = false;
double abs_d = fabs (d);
if (abs_d < UINTMAX_MAX + 1.0)
{
negative = d <= -1;
x = abs_d;
}
else
{
arg = double_to_integer (d);
goto bignum_arg;
}
}
p[0] = negative ? '-' : plus_flag ? '+' : ' ';
bool signedp = negative | plus_flag | space_flag;

View file

@ -165,13 +165,9 @@
(should (string-equal (format "%d" -18446744073709551616.0)
"-18446744073709551616")))
;; Perhaps Emacs will be improved someday to return the correct
;; answer for positive numbers instead of overflowing; in
;; that case these tests will need to be changed. In the meantime make
;; sure Emacs is reporting the overflow correctly.
(ert-deftest format-%x-large-float ()
(should-error (format "%x" 18446744073709551616.0)
:type 'overflow-error))
(should (string-equal (format "%x" 18446744073709551616.0)
"10000000000000000")))
(ert-deftest read-large-integer ()
(should (eq (type-of (read (format "%d0" most-negative-fixnum))) 'integer))
(should (eq (type-of (read (format "%+d" (* -8.0 most-negative-fixnum))))
@ -188,11 +184,16 @@
(dolist (val (list most-negative-fixnum (1+ most-negative-fixnum)
-1 0 1
(1- most-positive-fixnum) most-positive-fixnum))
(should (eq val (read (format fmt val)))))))
(should (eq val (read (format fmt val)))))
(dolist (val (list (1+ most-positive-fixnum)
(* 2 (1+ most-positive-fixnum))
(* 4 (1+ most-positive-fixnum))
(* 8 (1+ most-positive-fixnum))
18446744073709551616.0))
(should (= val (read (format fmt val)))))))
(ert-deftest format-%o-invalid-float ()
(should-error (format "%o" -1e-37)
:type 'overflow-error))
(ert-deftest format-%o-negative-float ()
(should (string-equal (format "%o" -1e-37) "0")))
;; Bug#31938
(ert-deftest format-%d-float ()