mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-10 07:10:06 +00:00
Fix spurious underflows from pow with results close to 1 (bug 14811).
This commit is contained in:
parent
0ab234b7db
commit
60e235ee2a
16
ChangeLog
16
ChangeLog
@ -1,3 +1,19 @@
|
|||||||
|
2012-11-07 Joseph Myers <joseph@codesourcery.com>
|
||||||
|
|
||||||
|
[BZ #14811]
|
||||||
|
* sysdeps/i386/fpu/e_powl.S (pm79): New object.
|
||||||
|
(__ieee754_powl): Saturate nonzero exponents with absolute value
|
||||||
|
below 0x1p-79 to +/- 0x1p-79.
|
||||||
|
* sysdeps/ieee754/dbl-64/e_pow.c (__ieee754_pow): Saturate nonzero
|
||||||
|
exponents with absolute value below 0x1p-64 to +/- 0x1p-64.
|
||||||
|
* sysdeps/ieee754/flt-32/e_powf.c (__ieee754_powf): Saturate
|
||||||
|
nonzero exponents with absolute value below 0x1p-32 to +/-
|
||||||
|
0x1p-32.
|
||||||
|
* sysdeps/x86_64/fpu/e_powl.S (pm79): New object.
|
||||||
|
(__ieee754_powl): Saturate nonzero exponents with absolute value
|
||||||
|
below 0x1p-79 to +/- 0x1p-79.
|
||||||
|
* math/libm-test.inc (pow_test): Add more tests.
|
||||||
|
|
||||||
2012-11-07 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
|
2012-11-07 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
|
||||||
|
|
||||||
* sysdeps/s390/dl-procinfo.c (_dl_s390_cap_flags): Sync
|
* sysdeps/s390/dl-procinfo.c (_dl_s390_cap_flags): Sync
|
||||||
|
2
NEWS
2
NEWS
@ -18,7 +18,7 @@ Version 2.17
|
|||||||
14518, 14519, 14530, 14532, 14538, 14543, 14544, 14545, 14557, 14562,
|
14518, 14519, 14530, 14532, 14538, 14543, 14544, 14545, 14557, 14562,
|
||||||
14568, 14576, 14579, 14583, 14587, 14595, 14602, 14610, 14621, 14638,
|
14568, 14576, 14579, 14583, 14587, 14595, 14602, 14610, 14621, 14638,
|
||||||
14645, 14648, 14652, 14660, 14661, 14669, 14683, 14694, 14716, 14743,
|
14645, 14648, 14652, 14660, 14661, 14669, 14683, 14694, 14716, 14743,
|
||||||
14767, 14783, 14784, 14785, 14793, 14796, 14797, 14801, 14805.
|
14767, 14783, 14784, 14785, 14793, 14796, 14797, 14801, 14805, 14811.
|
||||||
|
|
||||||
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
|
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
|
||||||
Optimized versions of memcpy, memset, and memcmp added for System z10 and
|
Optimized versions of memcpy, memset, and memcmp added for System z10 and
|
||||||
|
@ -7743,10 +7743,12 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, plus_infty, 1e-7L, plus_infty);
|
TEST_ff_f (pow, plus_infty, 1e-7L, plus_infty);
|
||||||
TEST_ff_f (pow, plus_infty, 1, plus_infty);
|
TEST_ff_f (pow, plus_infty, 1, plus_infty);
|
||||||
TEST_ff_f (pow, plus_infty, 1e7L, plus_infty);
|
TEST_ff_f (pow, plus_infty, 1e7L, plus_infty);
|
||||||
|
TEST_ff_f (pow, plus_infty, min_subnorm_value, plus_infty);
|
||||||
|
|
||||||
TEST_ff_f (pow, plus_infty, -1e-7L, 0);
|
TEST_ff_f (pow, plus_infty, -1e-7L, 0);
|
||||||
TEST_ff_f (pow, plus_infty, -1, 0);
|
TEST_ff_f (pow, plus_infty, -1, 0);
|
||||||
TEST_ff_f (pow, plus_infty, -1e7L, 0);
|
TEST_ff_f (pow, plus_infty, -1e7L, 0);
|
||||||
|
TEST_ff_f (pow, plus_infty, -min_subnorm_value, 0);
|
||||||
|
|
||||||
TEST_ff_f (pow, minus_infty, 1, minus_infty);
|
TEST_ff_f (pow, minus_infty, 1, minus_infty);
|
||||||
TEST_ff_f (pow, minus_infty, 11, minus_infty);
|
TEST_ff_f (pow, minus_infty, 11, minus_infty);
|
||||||
@ -7759,6 +7761,7 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, minus_infty, 1.1L, plus_infty);
|
TEST_ff_f (pow, minus_infty, 1.1L, plus_infty);
|
||||||
TEST_ff_f (pow, minus_infty, 11.1L, plus_infty);
|
TEST_ff_f (pow, minus_infty, 11.1L, plus_infty);
|
||||||
TEST_ff_f (pow, minus_infty, 1001.1L, plus_infty);
|
TEST_ff_f (pow, minus_infty, 1001.1L, plus_infty);
|
||||||
|
TEST_ff_f (pow, minus_infty, min_subnorm_value, plus_infty);
|
||||||
|
|
||||||
TEST_ff_f (pow, minus_infty, -1, minus_zero);
|
TEST_ff_f (pow, minus_infty, -1, minus_zero);
|
||||||
TEST_ff_f (pow, minus_infty, -11, minus_zero);
|
TEST_ff_f (pow, minus_infty, -11, minus_zero);
|
||||||
@ -7771,6 +7774,7 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, minus_infty, -1.1L, 0);
|
TEST_ff_f (pow, minus_infty, -1.1L, 0);
|
||||||
TEST_ff_f (pow, minus_infty, -11.1L, 0);
|
TEST_ff_f (pow, minus_infty, -11.1L, 0);
|
||||||
TEST_ff_f (pow, minus_infty, -1001.1L, 0);
|
TEST_ff_f (pow, minus_infty, -1001.1L, 0);
|
||||||
|
TEST_ff_f (pow, minus_infty, -min_subnorm_value, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST_ff_f (pow, nan_value, nan_value, nan_value);
|
TEST_ff_f (pow, nan_value, nan_value, nan_value);
|
||||||
@ -7793,6 +7797,8 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, nan_value, minus_infty, nan_value);
|
TEST_ff_f (pow, nan_value, minus_infty, nan_value);
|
||||||
TEST_ff_f (pow, nan_value, 2.5, nan_value);
|
TEST_ff_f (pow, nan_value, 2.5, nan_value);
|
||||||
TEST_ff_f (pow, nan_value, -2.5, nan_value);
|
TEST_ff_f (pow, nan_value, -2.5, nan_value);
|
||||||
|
TEST_ff_f (pow, nan_value, min_subnorm_value, nan_value);
|
||||||
|
TEST_ff_f (pow, nan_value, -min_subnorm_value, nan_value);
|
||||||
|
|
||||||
TEST_ff_f (pow, 1, plus_infty, 1);
|
TEST_ff_f (pow, 1, plus_infty, 1);
|
||||||
TEST_ff_f (pow, -1, plus_infty, 1);
|
TEST_ff_f (pow, -1, plus_infty, 1);
|
||||||
@ -7806,6 +7812,8 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, 1, 0x1p63L, 1);
|
TEST_ff_f (pow, 1, 0x1p63L, 1);
|
||||||
TEST_ff_f (pow, 1, 0x1p64L, 1);
|
TEST_ff_f (pow, 1, 0x1p64L, 1);
|
||||||
TEST_ff_f (pow, 1, 0x1p72L, 1);
|
TEST_ff_f (pow, 1, 0x1p72L, 1);
|
||||||
|
TEST_ff_f (pow, 1, min_subnorm_value, 1);
|
||||||
|
TEST_ff_f (pow, 1, -min_subnorm_value, 1);
|
||||||
|
|
||||||
/* pow (x, +-0) == 1. */
|
/* pow (x, +-0) == 1. */
|
||||||
TEST_ff_f (pow, plus_infty, 0, 1);
|
TEST_ff_f (pow, plus_infty, 0, 1);
|
||||||
@ -7825,6 +7833,10 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, -0.1L, -1.1L, nan_value, INVALID_EXCEPTION);
|
TEST_ff_f (pow, -0.1L, -1.1L, nan_value, INVALID_EXCEPTION);
|
||||||
TEST_ff_f (pow, -10.1L, 1.1L, nan_value, INVALID_EXCEPTION);
|
TEST_ff_f (pow, -10.1L, 1.1L, nan_value, INVALID_EXCEPTION);
|
||||||
TEST_ff_f (pow, -10.1L, -1.1L, nan_value, INVALID_EXCEPTION);
|
TEST_ff_f (pow, -10.1L, -1.1L, nan_value, INVALID_EXCEPTION);
|
||||||
|
TEST_ff_f (pow, -1.01L, min_subnorm_value, nan_value, INVALID_EXCEPTION);
|
||||||
|
TEST_ff_f (pow, -1.01L, -min_subnorm_value, nan_value, INVALID_EXCEPTION);
|
||||||
|
TEST_ff_f (pow, -1.0L, min_subnorm_value, nan_value, INVALID_EXCEPTION);
|
||||||
|
TEST_ff_f (pow, -1.0L, -min_subnorm_value, nan_value, INVALID_EXCEPTION);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
TEST_ff_f (pow, 0, -1, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
TEST_ff_f (pow, 0, -1, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
||||||
@ -7910,6 +7922,9 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, 0, -11.1L, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
TEST_ff_f (pow, 0, -11.1L, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
||||||
check_int ("errno for pow(0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
check_int ("errno for pow(0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
TEST_ff_f (pow, 0, -min_subnorm_value, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
||||||
|
check_int ("errno for pow(0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
||||||
|
errno = 0;
|
||||||
TEST_ff_f (pow, 0, -0x1p24, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
TEST_ff_f (pow, 0, -0x1p24, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
||||||
check_int ("errno for pow(0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
check_int ("errno for pow(0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -7925,6 +7940,9 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, minus_zero, -11.1L, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
TEST_ff_f (pow, minus_zero, -11.1L, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
||||||
check_int ("errno for pow(-0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
check_int ("errno for pow(-0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
TEST_ff_f (pow, minus_zero, -min_subnorm_value, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
||||||
|
check_int ("errno for pow(-0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
||||||
|
errno = 0;
|
||||||
TEST_ff_f (pow, minus_zero, -0x1p24, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
TEST_ff_f (pow, minus_zero, -0x1p24, plus_infty, DIVIDE_BY_ZERO_EXCEPTION);
|
||||||
check_int ("errno for pow(-0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
check_int ("errno for pow(-0,-num) == ERANGE", errno, ERANGE, 0, 0, 0);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -8114,12 +8132,14 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, 0.0, 0x1p24, 0.0);
|
TEST_ff_f (pow, 0.0, 0x1p24, 0.0);
|
||||||
TEST_ff_f (pow, 0.0, 0x1p127, 0.0);
|
TEST_ff_f (pow, 0.0, 0x1p127, 0.0);
|
||||||
TEST_ff_f (pow, 0.0, max_value, 0.0);
|
TEST_ff_f (pow, 0.0, max_value, 0.0);
|
||||||
|
TEST_ff_f (pow, 0.0, min_subnorm_value, 0.0);
|
||||||
|
|
||||||
/* pow (-0, y) == +0 for y > 0 and not an odd integer. */
|
/* pow (-0, y) == +0 for y > 0 and not an odd integer. */
|
||||||
TEST_ff_f (pow, minus_zero, 4, 0.0);
|
TEST_ff_f (pow, minus_zero, 4, 0.0);
|
||||||
TEST_ff_f (pow, minus_zero, 0x1p24, 0.0);
|
TEST_ff_f (pow, minus_zero, 0x1p24, 0.0);
|
||||||
TEST_ff_f (pow, minus_zero, 0x1p127, 0.0);
|
TEST_ff_f (pow, minus_zero, 0x1p127, 0.0);
|
||||||
TEST_ff_f (pow, minus_zero, max_value, 0.0);
|
TEST_ff_f (pow, minus_zero, max_value, 0.0);
|
||||||
|
TEST_ff_f (pow, minus_zero, min_subnorm_value, 0.0);
|
||||||
|
|
||||||
TEST_ff_f (pow, 16, 0.25L, 2);
|
TEST_ff_f (pow, 16, 0.25L, 2);
|
||||||
TEST_ff_f (pow, 0x1p64L, 0.125L, 256);
|
TEST_ff_f (pow, 0x1p64L, 0.125L, 256);
|
||||||
@ -8407,6 +8427,15 @@ pow_test (void)
|
|||||||
TEST_ff_f (pow, 0x1.0000000000001p0L, -0x1.23456789abcdfp61L, 1.0118762747828234466621210689458255908670e-253L);
|
TEST_ff_f (pow, 0x1.0000000000001p0L, -0x1.23456789abcdfp61L, 1.0118762747828234466621210689458255908670e-253L);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST_ff_f (pow, min_subnorm_value, min_subnorm_value, 1.0L);
|
||||||
|
TEST_ff_f (pow, min_subnorm_value, -min_subnorm_value, 1.0L);
|
||||||
|
TEST_ff_f (pow, max_value, min_subnorm_value, 1.0L);
|
||||||
|
TEST_ff_f (pow, max_value, -min_subnorm_value, 1.0L);
|
||||||
|
TEST_ff_f (pow, 0.99L, min_subnorm_value, 1.0L);
|
||||||
|
TEST_ff_f (pow, 0.99L, -min_subnorm_value, 1.0L);
|
||||||
|
TEST_ff_f (pow, 1.01L, min_subnorm_value, 1.0L);
|
||||||
|
TEST_ff_f (pow, 1.01L, -min_subnorm_value, 1.0L);
|
||||||
|
|
||||||
TEST_ff_f (pow, 2.0L, -100000.0L, plus_zero, UNDERFLOW_EXCEPTION);
|
TEST_ff_f (pow, 2.0L, -100000.0L, plus_zero, UNDERFLOW_EXCEPTION);
|
||||||
|
|
||||||
END (pow);
|
END (pow);
|
||||||
|
@ -38,6 +38,9 @@ p64: .byte 0, 0, 0, 0, 0, 0, 0xf0, 0x43
|
|||||||
.type p78,@object
|
.type p78,@object
|
||||||
p78: .byte 0, 0, 0, 0, 0, 0, 0xd0, 0x44
|
p78: .byte 0, 0, 0, 0, 0, 0, 0xd0, 0x44
|
||||||
ASM_SIZE_DIRECTIVE(p78)
|
ASM_SIZE_DIRECTIVE(p78)
|
||||||
|
.type pm79,@object
|
||||||
|
pm79: .byte 0, 0, 0, 0, 0, 0, 0, 0x3b
|
||||||
|
ASM_SIZE_DIRECTIVE(pm79)
|
||||||
|
|
||||||
.section .rodata.cst16,"aM",@progbits,16
|
.section .rodata.cst16,"aM",@progbits,16
|
||||||
|
|
||||||
@ -120,9 +123,25 @@ ENTRY(__ieee754_powl)
|
|||||||
fucomp %st(1) // y : x
|
fucomp %st(1) // y : x
|
||||||
fnstsw
|
fnstsw
|
||||||
sahf
|
sahf
|
||||||
jne 3f
|
je 9f
|
||||||
|
|
||||||
/* OK, we have an integer value for y. */
|
// If y has absolute value at most 0x1p-79, then any finite
|
||||||
|
// nonzero x will result in 1. Saturate y to those bounds to
|
||||||
|
// avoid underflow in the calculation of y*log2(x).
|
||||||
|
fld %st // y : y : x
|
||||||
|
fabs // |y| : y : x
|
||||||
|
fcompl MO(pm79) // y : x
|
||||||
|
fnstsw
|
||||||
|
sahf
|
||||||
|
jnc 3f
|
||||||
|
fstp %st(0) // pop y
|
||||||
|
fldl MO(pm79) // 0x1p-79 : x
|
||||||
|
testb $2, %dl
|
||||||
|
jnz 3f // y > 0
|
||||||
|
fchs // -0x1p-79 : x
|
||||||
|
jmp 3f
|
||||||
|
|
||||||
|
9: /* OK, we have an integer value for y. */
|
||||||
popl %eax
|
popl %eax
|
||||||
cfi_adjust_cfa_offset (-4)
|
cfi_adjust_cfa_offset (-4)
|
||||||
popl %edx
|
popl %edx
|
||||||
|
@ -90,6 +90,10 @@ __ieee754_pow(double x, double y) {
|
|||||||
|
|
||||||
SET_RESTORE_ROUND (FE_TONEAREST);
|
SET_RESTORE_ROUND (FE_TONEAREST);
|
||||||
|
|
||||||
|
/* Avoid internal underflow for tiny y. The exact value of y does
|
||||||
|
not matter if |y| <= 2**-64. */
|
||||||
|
if (ABS (y) < 0x1p-64)
|
||||||
|
y = y < 0 ? -0x1p-64 : 0x1p-64;
|
||||||
z = log1(x,&aa,&error); /* x^y =e^(y log (X)) */
|
z = log1(x,&aa,&error); /* x^y =e^(y log (X)) */
|
||||||
t = y*134217729.0;
|
t = y*134217729.0;
|
||||||
y1 = t - (t-y);
|
y1 = t - (t-y);
|
||||||
|
@ -141,6 +141,10 @@ __ieee754_powf(float x, float y)
|
|||||||
t2 = v-(t1-u);
|
t2 = v-(t1-u);
|
||||||
} else {
|
} else {
|
||||||
float s2,s_h,s_l,t_h,t_l;
|
float s2,s_h,s_l,t_h,t_l;
|
||||||
|
/* Avoid internal underflow for tiny y. The exact value
|
||||||
|
of y does not matter if |y| <= 2**-32. */
|
||||||
|
if (iy < 0x2f800000)
|
||||||
|
SET_FLOAT_WORD (y, (hy & 0x80000000) | 0x2f800000);
|
||||||
n = 0;
|
n = 0;
|
||||||
/* take care subnormal number */
|
/* take care subnormal number */
|
||||||
if(ix<0x00800000)
|
if(ix<0x00800000)
|
||||||
|
@ -38,6 +38,9 @@ p64: .byte 0, 0, 0, 0, 0, 0, 0xf0, 0x43
|
|||||||
.type p78,@object
|
.type p78,@object
|
||||||
p78: .byte 0, 0, 0, 0, 0, 0, 0xd0, 0x44
|
p78: .byte 0, 0, 0, 0, 0, 0, 0xd0, 0x44
|
||||||
ASM_SIZE_DIRECTIVE(p78)
|
ASM_SIZE_DIRECTIVE(p78)
|
||||||
|
.type pm79,@object
|
||||||
|
pm79: .byte 0, 0, 0, 0, 0, 0, 0, 0x3b
|
||||||
|
ASM_SIZE_DIRECTIVE(pm79)
|
||||||
|
|
||||||
.section .rodata.cst16,"aM",@progbits,16
|
.section .rodata.cst16,"aM",@progbits,16
|
||||||
|
|
||||||
@ -110,9 +113,25 @@ ENTRY(__ieee754_powl)
|
|||||||
fistpll -8(%rsp) // y : x
|
fistpll -8(%rsp) // y : x
|
||||||
fildll -8(%rsp) // int(y) : y : x
|
fildll -8(%rsp) // int(y) : y : x
|
||||||
fucomip %st(1),%st // y : x
|
fucomip %st(1),%st // y : x
|
||||||
jne 3f
|
je 9f
|
||||||
|
|
||||||
/* OK, we have an integer value for y. */
|
// If y has absolute value at most 0x1p-79, then any finite
|
||||||
|
// nonzero x will result in 1. Saturate y to those bounds to
|
||||||
|
// avoid underflow in the calculation of y*log2(x).
|
||||||
|
fldl MO(pm79) // 0x1p-79 : y : x
|
||||||
|
fld %st(1) // y : 0x1p-79 : y : x
|
||||||
|
fabs // |y| : 0x1p-79 : y : x
|
||||||
|
fcomip %st(1), %st // 0x1p-79 : y : x
|
||||||
|
fstp %st(0) // y : x
|
||||||
|
jnc 3f
|
||||||
|
fstp %st(0) // pop y
|
||||||
|
fldl MO(pm79) // 0x1p-79 : x
|
||||||
|
testb $2, %dl
|
||||||
|
jnz 3f // y > 0
|
||||||
|
fchs // -0x1p-79 : x
|
||||||
|
jmp 3f
|
||||||
|
|
||||||
|
9: /* OK, we have an integer value for y. */
|
||||||
mov -8(%rsp),%eax
|
mov -8(%rsp),%eax
|
||||||
mov -4(%rsp),%edx
|
mov -4(%rsp),%edx
|
||||||
orl $0, %edx
|
orl $0, %edx
|
||||||
|
Loading…
Reference in New Issue
Block a user