1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* numeric.c (flo_round): Avoid overflow by optimizing for trivial cases

[Bug ]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@33140 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
marcandre 2011-08-31 04:13:00 +00:00
parent 800081d0c8
commit 64e0cae274
2 changed files with 31 additions and 4 deletions

View file

@ -1,3 +1,8 @@
Wed Aug 31 13:09:41 2011 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
* numeric.c (flo_round): Avoid overflow by optimizing for trivial
cases [Bug #5227]
Wed Aug 31 00:50:01 2011 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.c (rb_w32_select_with_thread): and my typo. we all must

View file

@ -1491,18 +1491,40 @@ flo_round(int argc, VALUE *argv, VALUE num)
VALUE nd;
double number, f;
int ndigits = 0;
int binexp;
long val;
if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) {
ndigits = NUM2INT(nd);
}
number = RFLOAT_VALUE(num);
f = pow(10, abs(ndigits));
frexp (number , &binexp);
if (isinf(f)) {
if (ndigits < 0) number = 0;
/* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}",
i.e. such that 10 ** (exp - 1) <= |number| < 10 ** exp
Recall that up to 17 digits can be needed to represent a double,
so if ndigits + exp >= 17, the intermediate value (number * 10 ** ndigits)
will be an integer and thus the result is the original number.
If ndigits + exp <= 0, the result is 0 or "1e#{exp}", so
if ndigits + exp < 0, the result is 0.
We have:
2 ** (binexp-1) <= |number| < 2 ** binexp
10 ** ((binexp-1)/log_2(10)) <= |number| < 10 ** (binexp/log_2(10))
If binexp >= 0, and since log_2(10) = 3.322259:
10 ** (binexp/4 - 1) < |number| < 10 ** (binexp/3)
binexp/4 <= exp <= binexp/3
If binexp <= 0, swap the /4 and the /3
So if ndigits + binexp/(4 or 3) >= 17, the result is number
If ndigits + binexp/(3 or 4) < 0 the result is 0
*/
if (isinf(number) || isnan(number)) {
/* Do nothing */
}
else {
else if ((long)ndigits * (4 - (binexp > 0)) + binexp < 0) {
number = 0;
}
else if (((long)ndigits - 17) * (3 + (binexp > 0)) + binexp < 0) {
f = pow(10, abs(ndigits));
if (ndigits < 0) {
double absnum = fabs(number);
if (absnum < f) return INT2FIX(0);