Strange NSDate behavior building 32 bit v 64 bit (Richard Sepulveda)
Here is an update on what is going on with the NSDate issues. i have been working with 3 version's of MacRuby. MacRuby 0.7 with Vincent's first suggested modification (commenting out the NSDate clause in objc.m (This essentially makes MacRuby use a real NSDate object instead of converting it into a Ruby Time object) MacRuby 0.8 with no changes MacRuby 0.9 with Vincent's NSDate changes. (He fixes the NSDate/Ruby Time object) The test code: NSLog( "In rb_main.rb") i = 1296445544 NSLog( "i = %d class = %s" % [i, i.class.to_s]) f = 1296445544.0 NSLog( "f = %f class = %@ DIG = %d" % [ f, f.class, Float::DIG.to_s]) if i == f NSLog( "Is equal") else NSLog( "Not equal") end time = Time.new NSLog( "time = %s" % [time.to_s]) NSLog( "time to_i = %d" % [time.to_i]) NSLog( "time to_f = %f" % [time.to_f]) nsdate = NSDate.date NSLog( "nsdate = %s" % [nsdate.description]) i = nsdate.timeIntervalSinceReferenceDate.to_i f = nsdate.timeIntervalSinceReferenceDate.to_f NSLog( "nsdate to_i = %d" % [i]) NSLog( "nsdate to_f = %f" % [f]) Summary (all tests were run in 32 bit mode): I can provide the output if you wish to see it. MacRuby 0.7 - NSDate is fixed, Can also do calculations with the date like adding 60 seconds,etc. - Ruby Time - date is correct, to_i is correct, to_f is incorrect - Bignum.to_i is correct, Bignum.to_f is wrong MacRuby 0.8 - NSDate is broken - wrong time, wrong to_i, wrong to_f - Ruby Time - date is correct, to_i is correct, to_f is incorrect - Bignum.to_i is correct, Bignum.to_f is wrong MacRuby 0.9 - NSDate is somewhat fixed. It returns the correct time, but fails when doing calculations with that date - Ruby Time - date is correct, to_i is correct, to_f is incorrect - Bignum.to_i is correct, Bignum.to_f is wrong My conclusions, - 0.7 and 0.9 fix return the correct time now, 0.9 fix can't do necessary time arithmetic - Ruby Time.to_f is broken in all 3 versions - Bignum.to_f is broken in all 3 versions - I believe the to_f method is behind all of these problems but i haven't had time to find the problem nor a solution. * Late breaking news, I was running my real app with the modified 0.7 version and when i attempted to 'play' an NSSound, the application exited with a return code 45?? I am not sure what this means. I will try to create a test case for this later on.
My conclusions, - 0.7 and 0.9 fix return the correct time now, 0.9 fix can't do necessary time arithmetic - Ruby Time.to_f is broken in all 3 versions - Bignum.to_f is broken in all 3 versions - I believe the to_f method is behind all of these problems but i haven't had time to find the problem nor a solution.
Your problems with #to_f are due to the fact that 32-bit MacRuby stores floats in 30 bits (MRI stores them in objects in 64 bits, 64-bit MacRuby stores them in 62 bits). The reason is mainly speed related (and we also don't have to garbage-collect them). At some time I think we had 32-bit mode using objects for storing them like MRI, and 64-bit mode using 62 bits but we decided to handle them the same way in both modes to have less code to maintain. Seeing that very few people using 32-bit (and we will probably stop "supporting" it after 0.9), you will never get the precision you want from them. What you can do with MacRuby's current state though: - if you don't need sub-second precision, use #to_i and do computations in integers (you can us Time.at to bring them back in Time instances), - if you really need sub-second prevision, you would have to use BigDecimal. To convert a Time into BigDecimal: BigDecimal.new("%d.%06d" % [time.tv_sec, time.tv_usec]). To convert a BigDecimal back to time: Time.at(bd.to_i, (bd * 1000000).to_i % 1000000)
Thanks for looking into that Vincent. My 2 cents, for what it is worth: - NEVER use floating point for equality checks. Ever. Not only is the precision misleading (Radix 2 - isms/ etc.), but 32 vs. 64 ... etc. get in the way, quite often, in fact - If NSDate in particular, "always use NSDate methods of time calculations whenever possible" else - to_i (as Vincent lists) On Wed, 2 Feb 2011 08:20:40 +0900 Vincent Isambart <vincent.isambart@gmail.com> wrote:
My conclusions, - 0.7 and 0.9 fix return the correct time now, 0.9 fix can't do necessary time arithmetic - Ruby Time.to_f is broken in all 3 versions - Bignum.to_f is broken in all 3 versions - I believe the to_f method is behind all of these problems but i haven't had time to find the problem nor a solution.
Your problems with #to_f are due to the fact that 32-bit MacRuby stores floats in 30 bits (MRI stores them in objects in 64 bits, 64-bit MacRuby stores them in 62 bits). The reason is mainly speed related (and we also don't have to garbage-collect them). At some time I think we had 32-bit mode using objects for storing them like MRI, and 64-bit mode using 62 bits but we decided to handle them the same way in both modes to have less code to maintain.
Seeing that very few people using 32-bit (and we will probably stop "supporting" it after 0.9), you will never get the precision you want from them. What you can do with MacRuby's current state though: - if you don't need sub-second precision, use #to_i and do computations in integers (you can us Time.at to bring them back in Time instances), - if you really need sub-second prevision, you would have to use BigDecimal. To convert a Time into BigDecimal: BigDecimal.new("%d.%06d" % [time.tv_sec, time.tv_usec]). To convert a BigDecimal back to time: Time.at(bd.to_i, (bd * 1000000).to_i % 1000000) _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
participants (3)
-
macruby@djc.net
-
Richard Sepulveda
-
Vincent Isambart