ruby-changes:21109
From: nobu <ko1@a...>
Date: Fri, 2 Sep 2011 01:07:28 +0900 (JST)
Subject: [ruby-changes:21109] nobu:r33158 (trunk): * numeric.c (flo_round): substitute machine dependent magic number.
nobu 2011-09-02 01:07:16 +0900 (Fri, 02 Sep 2011) New Revision: 33158 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=33158 Log: * numeric.c (flo_round): substitute machine dependent magic number. Modified files: trunk/ChangeLog trunk/numeric.c trunk/test/ruby/test_float.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 33157) +++ ChangeLog (revision 33158) @@ -1,3 +1,7 @@ +Fri Sep 2 01:07:14 2011 Nobuyoshi Nakada <nobu@r...> + + * numeric.c (flo_round): substitute machine dependent magic number. + Thu Sep 1 17:31:22 2011 Nobuyoshi Nakada <nobu@r...> * insns.def (defineclass), vm_insnhelper.c (vm_get_cvar_base): see Index: numeric.c =================================================================== --- numeric.c (revision 33157) +++ numeric.c (revision 33158) @@ -1493,17 +1493,18 @@ int ndigits = 0; int binexp; long val; + enum {float_dig = DBL_DIG+2}; if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) { ndigits = NUM2INT(nd); } number = RFLOAT_VALUE(num); - frexp (number , &binexp); + frexp(number, &binexp); /* 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) + Recall that up to float_dig digits can be needed to represent a double, + so if ndigits + exp >= float_dig, 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. @@ -1514,7 +1515,7 @@ 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 + 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 (isinf(number) || isnan(number)) { @@ -1523,7 +1524,7 @@ else if ((long)ndigits * (4 - (binexp > 0)) + binexp < 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)); if (ndigits < 0) { double absnum = fabs(number); Index: test/ruby/test_float.rb =================================================================== --- test/ruby/test_float.rb (revision 33157) +++ test/ruby/test_float.rb (revision 33158) @@ -315,7 +315,9 @@ assert_raise(FloatDomainError) { inf.ceil } assert_raise(FloatDomainError) { inf.round } assert_raise(FloatDomainError) { inf.truncate } + end + def test_round_with_precision assert_equal(1.100, 1.111.round(1)) assert_equal(1.110, 1.111.round(2)) assert_equal(11110.0, 11111.1.round(-1)) @@ -323,6 +325,17 @@ 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 VS = [ -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/