mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* numeric.c (flo_round): substitute machine dependent magic number.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@33158 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
43284b6bf8
commit
c4eb2983ba
3 changed files with 23 additions and 5 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
Fri Sep 2 01:07:14 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* numeric.c (flo_round): substitute machine dependent magic number.
|
||||||
|
|
||||||
Thu Sep 1 17:31:22 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Thu Sep 1 17:31:22 2011 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* insns.def (defineclass), vm_insnhelper.c (vm_get_cvar_base): see
|
* insns.def (defineclass), vm_insnhelper.c (vm_get_cvar_base): see
|
||||||
|
|
11
numeric.c
11
numeric.c
|
@ -1493,17 +1493,18 @@ flo_round(int argc, VALUE *argv, VALUE num)
|
||||||
int ndigits = 0;
|
int ndigits = 0;
|
||||||
int binexp;
|
int binexp;
|
||||||
long val;
|
long val;
|
||||||
|
enum {float_dig = DBL_DIG+2};
|
||||||
|
|
||||||
if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) {
|
if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) {
|
||||||
ndigits = NUM2INT(nd);
|
ndigits = NUM2INT(nd);
|
||||||
}
|
}
|
||||||
number = RFLOAT_VALUE(num);
|
number = RFLOAT_VALUE(num);
|
||||||
frexp (number , &binexp);
|
frexp(number, &binexp);
|
||||||
|
|
||||||
/* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}",
|
/* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}",
|
||||||
i.e. such that 10 ** (exp - 1) <= |number| < 10 ** exp
|
i.e. such that 10 ** (exp - 1) <= |number| < 10 ** exp
|
||||||
Recall that up to 17 digits can be needed to represent a double,
|
Recall that up to float_dig digits can be needed to represent a double,
|
||||||
so if ndigits + exp >= 17, the intermediate value (number * 10 ** ndigits)
|
so if ndigits + exp >= float_dig, the intermediate value (number * 10 ** ndigits)
|
||||||
will be an integer and thus the result is the original number.
|
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 or "1e#{exp}", so
|
||||||
if ndigits + exp < 0, the result is 0.
|
if ndigits + exp < 0, the result is 0.
|
||||||
|
@ -1514,7 +1515,7 @@ flo_round(int argc, VALUE *argv, VALUE num)
|
||||||
10 ** (binexp/4 - 1) < |number| < 10 ** (binexp/3)
|
10 ** (binexp/4 - 1) < |number| < 10 ** (binexp/3)
|
||||||
binexp/4 <= exp <= binexp/3
|
binexp/4 <= exp <= binexp/3
|
||||||
If binexp <= 0, swap the /4 and the /3
|
If binexp <= 0, swap the /4 and the /3
|
||||||
So if ndigits + binexp/(4 or 3) >= 17, the result is number
|
So if ndigits + binexp/(4 or 3) >= float_dig, the result is number
|
||||||
If ndigits + binexp/(3 or 4) < 0 the result is 0
|
If ndigits + binexp/(3 or 4) < 0 the result is 0
|
||||||
*/
|
*/
|
||||||
if (isinf(number) || isnan(number)) {
|
if (isinf(number) || isnan(number)) {
|
||||||
|
@ -1523,7 +1524,7 @@ flo_round(int argc, VALUE *argv, VALUE num)
|
||||||
else if ((long)ndigits * (4 - (binexp > 0)) + binexp < 0) {
|
else if ((long)ndigits * (4 - (binexp > 0)) + binexp < 0) {
|
||||||
number = 0;
|
number = 0;
|
||||||
}
|
}
|
||||||
else if (((long)ndigits - 17) * (3 + (binexp > 0)) + binexp < 0) {
|
else if (((long)ndigits - float_dig) * (3 + (binexp > 0)) + binexp < 0) {
|
||||||
f = pow(10, abs(ndigits));
|
f = pow(10, abs(ndigits));
|
||||||
if (ndigits < 0) {
|
if (ndigits < 0) {
|
||||||
double absnum = fabs(number);
|
double absnum = fabs(number);
|
||||||
|
|
|
@ -315,7 +315,9 @@ class TestFloat < Test::Unit::TestCase
|
||||||
assert_raise(FloatDomainError) { inf.ceil }
|
assert_raise(FloatDomainError) { inf.ceil }
|
||||||
assert_raise(FloatDomainError) { inf.round }
|
assert_raise(FloatDomainError) { inf.round }
|
||||||
assert_raise(FloatDomainError) { inf.truncate }
|
assert_raise(FloatDomainError) { inf.truncate }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_round_with_precision
|
||||||
assert_equal(1.100, 1.111.round(1))
|
assert_equal(1.100, 1.111.round(1))
|
||||||
assert_equal(1.110, 1.111.round(2))
|
assert_equal(1.110, 1.111.round(2))
|
||||||
assert_equal(11110.0, 11111.1.round(-1))
|
assert_equal(11110.0, 11111.1.round(-1))
|
||||||
|
@ -323,6 +325,17 @@ class TestFloat < Test::Unit::TestCase
|
||||||
|
|
||||||
assert_equal(10**300, 1.1e300.round(-300))
|
assert_equal(10**300, 1.1e300.round(-300))
|
||||||
assert_equal(-10**300, -1.1e300.round(-300))
|
assert_equal(-10**300, -1.1e300.round(-300))
|
||||||
|
assert_equal(1.0e-300, 1.1e-300.round(300))
|
||||||
|
assert_equal(-1.0e-300, -1.1e-300.round(300))
|
||||||
|
|
||||||
|
bug5227 = '[ruby-core:39093]'
|
||||||
|
assert_equal(42.0, 42.0.round(308), bug5227)
|
||||||
|
assert_equal(1.0e307, 1.0e307.round(2), bug5227)
|
||||||
|
|
||||||
|
assert_raise(TypeError) {1.0.round("4")}
|
||||||
|
assert_raise(TypeError) {1.0.round(nil)}
|
||||||
|
def (prec = Object.new).to_int; 2; end
|
||||||
|
assert_equal(1.0, 0.998.round(prec))
|
||||||
end
|
end
|
||||||
|
|
||||||
VS = [
|
VS = [
|
||||||
|
|
Loading…
Reference in a new issue