summaryrefslogtreecommitdiff
path: root/spec/ruby/core/float/round_spec.rb
blob: 4bd2dc460c1e7c37bf9c9e7b9ff54787b8646fa9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require_relative '../../spec_helper'

describe "Float#round" do
  it "returns the nearest Integer" do
    5.5.round.should == 6
    0.4.round.should == 0
    0.6.round.should == 1
    -1.4.round.should == -1
    -2.8.round.should == -3
    0.0.round.should == 0
  end

  it "returns the nearest Integer for Float near the limit" do
    0.49999999999999994.round.should == 0
    -0.49999999999999994.round.should == 0
  end

  it "raises FloatDomainError for exceptional values" do
    -> { (+infinity_value).round }.should raise_error(FloatDomainError)
    -> { (-infinity_value).round }.should raise_error(FloatDomainError)
    -> { nan_value.round }.should raise_error(FloatDomainError)
  end

  it "rounds self to an optionally given precision" do
    5.5.round(0).should eql(6)
    5.7.round(1).should eql(5.7)
    1.2345678.round(2).should == 1.23
    123456.78.round(-2).should eql(123500) # rounded up
    -123456.78.round(-2).should eql(-123500)
    12.345678.round(3.999).should == 12.346
  end

  it "returns zero when passed a negative argument with magnitude greater than magnitude of the whole number portion of the Float" do
    0.8346268.round(-1).should eql(0)
  end

  it "raises a TypeError when its argument can not be converted to an Integer" do
    -> { 1.0.round("4") }.should raise_error(TypeError)
    -> { 1.0.round(nil) }.should raise_error(TypeError)
  end

  it "raises FloatDomainError for exceptional values when passed a non-positive precision" do
    -> { Float::INFINITY.round( 0) }.should raise_error(FloatDomainError)
    -> { Float::INFINITY.round(-2) }.should raise_error(FloatDomainError)
    -> { (-Float::INFINITY).round( 0) }.should raise_error(FloatDomainError)
    -> { (-Float::INFINITY).round(-2) }.should raise_error(FloatDomainError)
  end

  it "raises RangeError for NAN when passed a non-positive precision" do
    -> { Float::NAN.round(0) }.should raise_error(RangeError)
    -> { Float::NAN.round(-2) }.should raise_error(RangeError)
  end

  it "returns self for exceptional values when passed a non-negative precision" do
    Float::INFINITY.round(2).should == Float::INFINITY
    (-Float::INFINITY).round(2).should == -Float::INFINITY
    Float::NAN.round(2).should be_nan
  end

  # redmine:5227
  it "works for corner cases" do
    42.0.round(308).should eql(42.0)
    1.0e307.round(2).should eql(1.0e307)
  end

  # redmine:5271
  it "returns rounded values for big argument" do
    0.42.round(2.0**30).should == 0.42
  end

  it "returns big values rounded to nearest" do
    +2.5e20.round(-20).should   eql( +3 * 10 ** 20  )
    -2.5e20.round(-20).should   eql( -3 * 10 ** 20  )
  end

  # redmine #5272
  it "returns rounded values for big values" do
    +2.4e20.round(-20).should   eql( +2 * 10 ** 20  )
    -2.4e20.round(-20).should   eql( -2 * 10 ** 20  )
    +2.5e200.round(-200).should eql( +3 * 10 ** 200 )
    +2.4e200.round(-200).should eql( +2 * 10 ** 200 )
    -2.5e200.round(-200).should eql( -3 * 10 ** 200 )
    -2.4e200.round(-200).should eql( -2 * 10 ** 200 )
  end

  it "returns different rounded values depending on the half option" do
    2.5.round(half: nil).should      eql(3)
    2.5.round(half: :up).should      eql(3)
    2.5.round(half: :down).should    eql(2)
    2.5.round(half: :even).should    eql(2)
    3.5.round(half: nil).should      eql(4)
    3.5.round(half: :up).should      eql(4)
    3.5.round(half: :down).should    eql(3)
    3.5.round(half: :even).should    eql(4)
    (-2.5).round(half: nil).should   eql(-3)
    (-2.5).round(half: :up).should   eql(-3)
    (-2.5).round(half: :down).should eql(-2)
    (-2.5).round(half: :even).should eql(-2)
  end

  it "rounds self to an optionally given precision with a half option" do
    5.55.round(1, half: nil).should eql(5.6)
    5.55.round(1, half: :up).should eql(5.6)
    5.55.round(1, half: :down).should eql(5.5)
    5.55.round(1, half: :even).should eql(5.6)
  end

  it "raises FloatDomainError for exceptional values with a half option" do
    -> { (+infinity_value).round(half: :up) }.should raise_error(FloatDomainError)
    -> { (-infinity_value).round(half: :down) }.should raise_error(FloatDomainError)
    -> { nan_value.round(half: :even) }.should raise_error(FloatDomainError)
  end

  it "raise for a non-existent round mode" do
    -> { 14.2.round(half: :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode: nonsense")
  end

  describe "when 0.0 is given" do
    it "returns self for positive ndigits" do
      (0.0).round(5).inspect.should == "0.0"
      (-0.0).round(1).inspect.should == "-0.0"
    end

    it "returns 0 for 0 or undefined ndigits" do
      (0.0).round.should == 0
      (-0.0).round(0).should == 0
      (0.0).round(half: :up) == 0
    end
  end
end