diff options
| author | Paul Eggert | 2018-06-25 12:21:40 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-06-25 12:23:08 -0700 |
| commit | d0e2a341dd9a9a365fd311748df024ecb25b70ec (patch) | |
| tree | aa5b4e9f33777155349c3aacefece4d25199b887 | |
| parent | 27a21970f6faa9baf42823f731b7842b075e86eb (diff) | |
| download | emacs-d0e2a341dd9a9a365fd311748df024ecb25b70ec.tar.gz emacs-d0e2a341dd9a9a365fd311748df024ecb25b70ec.zip | |
(format "%d" F) now truncates floating F
Problem reported by Paul Pogonyshev (Bug#31938).
* src/editfns.c: Include math.h, for trunc.
(styled_format): For %d, truncate floating-point numbers and
convert -0 to 0, going back to how Emacs 26 did things.
* doc/lispref/strings.texi (Formatting Strings):
Document behavior of %o, %d, %x, %X on floating-point numbers.
* src/floatfns.c (trunc) [!HAVE_TRUNC]: Rename from emacs_trunc
and make it an extern function, so that editfns.c can use it.
All callers changed.
* test/src/editfns-tests.el (format-%d-float): New test.
| -rw-r--r-- | doc/lispref/strings.texi | 11 | ||||
| -rw-r--r-- | src/editfns.c | 7 | ||||
| -rw-r--r-- | src/floatfns.c | 13 | ||||
| -rw-r--r-- | src/lisp.h | 5 | ||||
| -rw-r--r-- | test/src/editfns-tests.el | 8 |
5 files changed, 32 insertions, 12 deletions
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 70ba1aa613e..026ba749cbd 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi | |||
| @@ -922,18 +922,23 @@ Functions}). Thus, strings are enclosed in @samp{"} characters, and | |||
| 922 | @item %o | 922 | @item %o |
| 923 | @cindex integer to octal | 923 | @cindex integer to octal |
| 924 | Replace the specification with the base-eight representation of an | 924 | Replace the specification with the base-eight representation of an |
| 925 | unsigned integer. | 925 | unsigned integer. The object can also be a nonnegative floating-point |
| 926 | number that is formatted as an integer, dropping any fraction, if the | ||
| 927 | integer does not exceed machine limits. | ||
| 926 | 928 | ||
| 927 | @item %d | 929 | @item %d |
| 928 | Replace the specification with the base-ten representation of a signed | 930 | Replace the specification with the base-ten representation of a signed |
| 929 | integer. | 931 | integer. The object can also be a floating-point number that is |
| 932 | formatted as an integer, dropping any fraction. | ||
| 930 | 933 | ||
| 931 | @item %x | 934 | @item %x |
| 932 | @itemx %X | 935 | @itemx %X |
| 933 | @cindex integer to hexadecimal | 936 | @cindex integer to hexadecimal |
| 934 | Replace the specification with the base-sixteen representation of an | 937 | Replace the specification with the base-sixteen representation of an |
| 935 | unsigned integer. @samp{%x} uses lower case and @samp{%X} uses upper | 938 | unsigned integer. @samp{%x} uses lower case and @samp{%X} uses upper |
| 936 | case. | 939 | case. The object can also be a nonnegative floating-point number that |
| 940 | is formatted as an integer, dropping any fraction, if the integer does | ||
| 941 | not exceed machine limits. | ||
| 937 | 942 | ||
| 938 | @item %c | 943 | @item %c |
| 939 | Replace the specification with the character which is the value given. | 944 | Replace the specification with the character which is the value given. |
diff --git a/src/editfns.c b/src/editfns.c index 30d585cd018..7d032a7ca4c 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -47,6 +47,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 47 | #include <errno.h> | 47 | #include <errno.h> |
| 48 | #include <float.h> | 48 | #include <float.h> |
| 49 | #include <limits.h> | 49 | #include <limits.h> |
| 50 | #include <math.h> | ||
| 50 | 51 | ||
| 51 | #ifdef HAVE_TIMEZONE_T | 52 | #ifdef HAVE_TIMEZONE_T |
| 52 | # include <sys/param.h> | 53 | # include <sys/param.h> |
| @@ -4671,6 +4672,12 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4671 | { | 4672 | { |
| 4672 | strcpy (f - pMlen - 1, "f"); | 4673 | strcpy (f - pMlen - 1, "f"); |
| 4673 | double x = XFLOAT_DATA (arg); | 4674 | double x = XFLOAT_DATA (arg); |
| 4675 | |||
| 4676 | /* Truncate and then convert -0 to 0, to be more | ||
| 4677 | consistent with %x etc.; see Bug#31938. */ | ||
| 4678 | x = trunc (x); | ||
| 4679 | x = x ? x : 0; | ||
| 4680 | |||
| 4674 | sprintf_bytes = sprintf (sprintf_buf, convspec, 0, x); | 4681 | sprintf_bytes = sprintf (sprintf_buf, convspec, 0, x); |
| 4675 | char c0 = sprintf_buf[0]; | 4682 | char c0 = sprintf_buf[0]; |
| 4676 | bool signedp = ! ('0' <= c0 && c0 <= '9'); | 4683 | bool signedp = ! ('0' <= c0 && c0 <= '9'); |
diff --git a/src/floatfns.c b/src/floatfns.c index ec0349fbf40..e7d404a84e0 100644 --- a/src/floatfns.c +++ b/src/floatfns.c | |||
| @@ -435,11 +435,9 @@ emacs_rint (double d) | |||
| 435 | } | 435 | } |
| 436 | #endif | 436 | #endif |
| 437 | 437 | ||
| 438 | #ifdef HAVE_TRUNC | 438 | #ifndef HAVE_TRUNC |
| 439 | #define emacs_trunc trunc | 439 | double |
| 440 | #else | 440 | trunc (double d) |
| 441 | static double | ||
| 442 | emacs_trunc (double d) | ||
| 443 | { | 441 | { |
| 444 | return (d < 0 ? ceil : floor) (d); | 442 | return (d < 0 ? ceil : floor) (d); |
| 445 | } | 443 | } |
| @@ -482,8 +480,7 @@ Rounds ARG toward zero. | |||
| 482 | With optional DIVISOR, truncate ARG/DIVISOR. */) | 480 | With optional DIVISOR, truncate ARG/DIVISOR. */) |
| 483 | (Lisp_Object arg, Lisp_Object divisor) | 481 | (Lisp_Object arg, Lisp_Object divisor) |
| 484 | { | 482 | { |
| 485 | return rounding_driver (arg, divisor, emacs_trunc, truncate2, | 483 | return rounding_driver (arg, divisor, trunc, truncate2, "truncate"); |
| 486 | "truncate"); | ||
| 487 | } | 484 | } |
| 488 | 485 | ||
| 489 | 486 | ||
| @@ -543,7 +540,7 @@ DEFUN ("ftruncate", Fftruncate, Sftruncate, 1, 1, 0, | |||
| 543 | { | 540 | { |
| 544 | CHECK_FLOAT (arg); | 541 | CHECK_FLOAT (arg); |
| 545 | double d = XFLOAT_DATA (arg); | 542 | double d = XFLOAT_DATA (arg); |
| 546 | d = emacs_trunc (d); | 543 | d = trunc (d); |
| 547 | return make_float (d); | 544 | return make_float (d); |
| 548 | } | 545 | } |
| 549 | 546 | ||
diff --git a/src/lisp.h b/src/lisp.h index d0c52d85672..8c884dce150 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3425,8 +3425,11 @@ extern Lisp_Object string_make_unibyte (Lisp_Object); | |||
| 3425 | extern void syms_of_fns (void); | 3425 | extern void syms_of_fns (void); |
| 3426 | 3426 | ||
| 3427 | /* Defined in floatfns.c. */ | 3427 | /* Defined in floatfns.c. */ |
| 3428 | extern void syms_of_floatfns (void); | 3428 | #ifndef HAVE_TRUNC |
| 3429 | extern double trunc (double); | ||
| 3430 | #endif | ||
| 3429 | extern Lisp_Object fmod_float (Lisp_Object x, Lisp_Object y); | 3431 | extern Lisp_Object fmod_float (Lisp_Object x, Lisp_Object y); |
| 3432 | extern void syms_of_floatfns (void); | ||
| 3430 | 3433 | ||
| 3431 | /* Defined in fringe.c. */ | 3434 | /* Defined in fringe.c. */ |
| 3432 | extern void syms_of_fringe (void); | 3435 | extern void syms_of_fringe (void); |
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el index 1ed0bd5bbaf..c828000bb4f 100644 --- a/test/src/editfns-tests.el +++ b/test/src/editfns-tests.el | |||
| @@ -176,6 +176,14 @@ | |||
| 176 | (should-error (format "%o" -1e-37) | 176 | (should-error (format "%o" -1e-37) |
| 177 | :type 'overflow-error)) | 177 | :type 'overflow-error)) |
| 178 | 178 | ||
| 179 | ;; Bug#31938 | ||
| 180 | (ert-deftest format-%d-float () | ||
| 181 | (should (string-equal (format "%d" -1.1) "-1")) | ||
| 182 | (should (string-equal (format "%d" -0.9) "0")) | ||
| 183 | (should (string-equal (format "%d" -0.0) "0")) | ||
| 184 | (should (string-equal (format "%d" 0.0) "0")) | ||
| 185 | (should (string-equal (format "%d" 0.9) "0")) | ||
| 186 | (should (string-equal (format "%d" 1.1) "1"))) | ||
| 179 | 187 | ||
| 180 | ;;; Check format-time-string with various TZ settings. | 188 | ;;; Check format-time-string with various TZ settings. |
| 181 | ;;; Use only POSIX-compatible TZ values, since the tests should work | 189 | ;;; Use only POSIX-compatible TZ values, since the tests should work |