Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-2741

Floats passed to Extensions::Time inaccuracy (since v3.0.14)

    • Type: Icon: Task Task
    • Resolution: Done
    • 3.0.20
    • Affects Version/s: None
    • Component/s: None
    • Labels:

      I'm getting some weird behavior from Mongoid::Extensions::Time when Floats are passed to it. Rounding errors..
      It doesn't happen on every float, but at least those with decimals. I haven't been able to determine the exact requirements for a float to be subject to this rounding error.
      The problem occurs in Mongoid v3.0.14 and all versions after that.

      The behavior was introduced in this commit: https://github.com/mongoid/mongoid/commit/b9aee40ef2a86c56fc72020b2064087c5e968502
      In this file, this line.

      This is what happens, code with an example spec:

      Mongoid 3.0.13

      The floats given to the class are the same ones I get back.

      class TimeTest
        include Mongoid::Document
        field :time, :type => Time
      end
      
      TimeTest.new(:time => 1.1).time.to_f
       => 1.1 
      TimeTest.new(:time => 2.1).time.to_f
       => 2.1 
      TimeTest.new(:time => 3.1).time.to_f
       => 3.1 
      TimeTest.new(:time => 4.1).time.to_f
       => 4.1 
      TimeTest.new(:time => 5.1).time.to_f
       => 5.1 
      TimeTest.new(:time => 6.1).time.to_f
       => 6.1 
      TimeTest.new(:time => 7.1).time.to_f
       => 7.1 
      TimeTest.new(:time => 8.1).time.to_f
       => 8.1 
      TimeTest.new(:time => 9.1).time.to_f
       => 9.1 
      TimeTest.new(:time => 10.1).time.to_f
       => 10.1 
      TimeTest.new(:time => 11.1).time.to_f
       => 11.1 
      TimeTest.new(:time => 15.1).time.to_f
       => 15.1 
      TimeTest.new(:time => 20.1).time.to_f
       => 20.1 
      TimeTest.new(:time => 25.1).time.to_f
       => 25.1 
      

      Mongoid 3.0.14

      Now the floats given to the class are modified, they lose their precision.

      # Using the same class
      
      TimeTest.new(:time => 1.1).time.to_f
       => 1.1 
      TimeTest.new(:time => 2.1).time.to_f
       => 2.1 
      TimeTest.new(:time => 3.1).time.to_f
       => 3.1 
      TimeTest.new(:time => 4.1).time.to_f
       => 4.099999999 # => So here it differs from the old behavior
      TimeTest.new(:time => 5.1).time.to_f
       => 5.099999999 
      TimeTest.new(:time => 6.1).time.to_f
       => 6.099999999 
      TimeTest.new(:time => 7.1).time.to_f
       => 7.099999999 
      TimeTest.new(:time => 8.1).time.to_f
       => 8.099999999 
      TimeTest.new(:time => 9.1).time.to_f
       => 9.099999999 
      TimeTest.new(:time => 10.1).time.to_f
       => 10.099999999 
      TimeTest.new(:time => 11.1).time.to_f
       => 11.099999999 
      TimeTest.new(:time => 15.1).time.to_f
       => 15.099999999 
      TimeTest.new(:time => 20.1).time.to_f
       => 20.1 
      TimeTest.new(:time => 25.1).time.to_f
       => 25.1
      

      Environment

      Running on Ruby 1.9.3p327. Example is made in a Rails 3.2.11 app with MongoDB 2.2.2.

      Example spec

      Very much an example spec: (Not sure how to exactly test all kinds of floats which could trigger this behavior.)

      context "when given a float" do
      
        it "stored the float accurately" do
          Time.mongoize(2500.1).to_f.should eq(2500.1)
        end
      end
      

      Result:

        1) Mongoid::Extensions::Time.mongoize when given a float stored the float accurately
           Failure/Error: Time.mongoize(2500.1).to_f.should eq(2500.1)
             
             expected: 2500.1
                  got: 2500.099999999
             
             (compared using ==)
           # ./spec/mongoid/extensions/time_spec.rb:189:in `block (4 levels) in <top (required)>'
      
      Finished in 0.14754 seconds
      44 examples, 1 failure
      

      In conclusion

      Is this expected behavior after this change or not?
      I realize this is miliseconds work, but I'd like to have my data the way I stored them.

            Assignee:
            Unassigned Unassigned
            Reporter:
            tombruijn tombruijn
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved: