summaryrefslogtreecommitdiff
path: root/sv.c
diff options
context:
space:
mode:
authorZefram <zefram@fysh.org>2018-01-19 05:05:07 +0000
committerZefram <zefram@fysh.org>2018-01-19 05:09:07 +0000
commit60fa46621ae5d0d44c802aedc205274584701fa0 (patch)
tree70bcd377015aeb2dc0bdd0321bbce0b70d7adb3f /sv.c
parent8c7aa727bdcea40fd6b4ffb9ca8bbf53c0fadb10 (diff)
downloadperl-60fa46621ae5d0d44c802aedc205274584701fa0.tar.gz
fix F0convert() on edge cases
The F0convert() function used to implement the %.0f format specifier more cheaply went wrong on some edge cases. Its rounding went wrong when the exponent is such that fractional values are not representable, making the "+= 0.5" invoke floating point rounding. Fix that by only invoking that rounding logic for values that start out fractional. That fixes the output part of [perl #47602]. It also failed to emit the sign for negative zero. Fix that by making it not apply to zero values.
Diffstat (limited to 'sv.c')
-rw-r--r--sv.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/sv.c b/sv.c
index 2c13b3b333..6ad33c0bfc 100644
--- a/sv.c
+++ b/sv.c
@@ -11057,12 +11057,15 @@ S_F0convert(NV nv, char *const endbuf, STRLEN *const len)
assert(!Perl_isinfnan(nv));
if (neg)
nv = -nv;
- if (nv < UV_MAX) {
+ if (nv != 0.0 && nv < UV_MAX) {
char *p = endbuf;
- nv += 0.5;
uv = (UV)nv;
- if (uv & 1 && uv == nv)
- uv--; /* Round to even */
+ if (uv != nv) {
+ nv += 0.5;
+ uv = (UV)nv;
+ if (uv & 1 && uv == nv)
+ uv--; /* Round to even */
+ }
do {
const unsigned dig = uv % 10;
*--p = '0' + dig;