Method: Float#round
- Defined in:
- numeric.c
#round([ndigits]) ⇒ Integer, Float
Rounds float to a given precision in decimal digits (default 0 digits).
Precision may be negative. Returns a floating point number when ndigits is more than zero.
1.4.round #=> 1
1.5.round #=> 2
1.6.round #=> 2
(-1.5).round #=> -2
1.234567.round(2) #=> 1.23
1.234567.round(3) #=> 1.235
1.234567.round(4) #=> 1.2346
1.234567.round(5) #=> 1.23457
34567.89.round(-5) #=> 0
34567.89.round(-4) #=> 30000
34567.89.round(-3) #=> 35000
34567.89.round(-2) #=> 34600
34567.89.round(-1) #=> 34570
34567.89.round(0) #=> 34568
34567.89.round(1) #=> 34567.9
34567.89.round(2) #=> 34567.89
34567.89.round(3) #=> 34567.89
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 |
# File 'numeric.c', line 1793
static VALUE
flo_round(int argc, VALUE *argv, VALUE num)
{
VALUE nd;
double number, f;
int ndigits = 0;
int binexp;
enum {float_dig = DBL_DIG+2};
if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) {
ndigits = NUM2INT(nd);
}
if (ndigits < 0) {
return int_round_0(flo_truncate(num), ndigits);
}
number = RFLOAT_VALUE(num);
if (ndigits == 0) {
return dbl2ival(number);
}
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 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.
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)
floor(binexp/4) <= exp <= ceil(binexp/3)
If binexp <= 0, swap the /4 and the /3
So if ndigits + floor(binexp/(4 or 3)) >= float_dig, the result is number
If ndigits + ceil(binexp/(3 or 4)) < 0 the result is 0
*/
if (isinf(number) || isnan(number) ||
(ndigits >= float_dig - (binexp > 0 ? binexp / 4 : binexp / 3 - 1))) {
return num;
}
if (ndigits < - (binexp > 0 ? binexp / 3 + 1 : binexp / 4)) {
return DBL2NUM(0);
}
f = pow(10, ndigits);
return DBL2NUM(round(number * f) / f);
}
|