Time#+ and usec

Hello,

The following results look buggy. I tried with Ruby 1.6.7 and 1.7.2.

(Time.at(0) + .1).usec # => 100000
(Time.at(0) + .2).usec # => 200000
(Time.at(0) + .3).usec # => 299999
(Time.at(0) + .4).usec # => 400000

···


mike

In article 8248e2a3.0209141306.7677f2d3@posting.google.com,
Michael Witrant wrote:

Hello,

The following results look buggy. I tried with Ruby 1.6.7 and 1.7.2.

(Time.at(0) + .1).usec # => 100000
(Time.at(0) + .2).usec # => 200000
(Time.at(0) + .3).usec # => 299999
(Time.at(0) + .4).usec # => 400000

Smells like floating point arithmetic in action to me … try

[0.1, 0.2, 0.3, 0.4, 0.5].each { |f|
puts ‘%.20f’ % f
}

And have a look at http://docs.sun.com/source/806-3568/ncg_goldberg.html

Hope this helps,

Mike

···


mike@stok.co.uk | The “`Stok’ disclaimers” apply.
http://www.stok.co.uk/~mike/ | GPG PGP Key 1024D/059913DA
mike@exegenix.com | Fingerprint 0570 71CD 6790 7C28 3D60
http://www.exegenix.com/ | 75D2 9EC4 C1C0 0599 13DA

Looks to me like your standard “base 10 numbers can’t necessarily be
represented exactly in a base 2 system” issue.

···

— Michael Witrant mike.pub@lepton.fr wrote:

Hello,

The following results look buggy. I tried with Ruby 1.6.7 and
1.7.2.

(Time.at(0) + .1).usec # => 100000
(Time.at(0) + .2).usec # => 200000
(Time.at(0) + .3).usec # => 299999
(Time.at(0) + .4).usec # => 400000

=====

Use your computer to help find a cure for cancer: http://members.ud.com/projects/cancer/

Yahoo IM: michael_s_campbell


Do you Yahoo!?
Yahoo! News - Today’s headlines

Yep. For example,

% ruby -rieee754hack -e’[0.1,0.2,0.3,0.4,0.5].each{|i| puts i.human_readable}’
+1 * 0b1.1001100110011001100110011001100110011001100110011010 * 2**(1019-1023)
+1 * 0b1.1001100110011001100110011001100110011001100110011010 * 2**(1020-1023)
+1 * 0b1.0011001100110011001100110011001100110011001100110011 * 2**(1021-1023)
+1 * 0b1.1001100110011001100110011001100110011001100110011010 * 2**(1021-1023)
+1 * 0b1.0000000000000000000000000000000000000000000000000000 * 2**(1022-1023)
%

But my FreeBSD box reports 100000, 200000, 300000 and 400000 for
(Time.at(0)+0.1).usec etc. The result seems to depend on the
implementation of modf(3) which is used in time.c:time_plus().

– Gotoken

···

At Sun, 15 Sep 2002 09:02:57 +0900, Michael Campbell wrote:

(Time.at(0) + .1).usec # => 100000
(Time.at(0) + .2).usec # => 200000
(Time.at(0) + .3).usec # => 299999
(Time.at(0) + .4).usec # => 400000

Looks to me like your standard “base 10 numbers can’t necessarily be
represented exactly in a base 2 system” issue.

This is not the whole story IMHO. You have to take rounding issues in
account. If ruby rounded the value to full microseconds in the usual way,
you would see 300000 instead of 299999. The precision of a double is still
just enough to discriminate full microseconds in a date (when zero is
1970/1/1 and proper rounding is applied).

I don’t know for sure, but I suspect that ruby is always rounding down
dates and times by intention – otherwise, what would happen to

Time.utc(1970,12,31,23,59,59,999999) + .9e-6

Rounding up the microseconds value may also alter everything else in the
date, including the year. Would you want that?

Tobias

···

On Sat, 14 Sep 2002, Mike Stok wrote:

In article 8248e2a3.0209141306.7677f2d3@posting.google.com,
Michael Witrant wrote:

Hello,

The following results look buggy. I tried with Ruby 1.6.7 and 1.7.2.

(Time.at(0) + .1).usec # => 100000
(Time.at(0) + .2).usec # => 200000
(Time.at(0) + .3).usec # => 299999
(Time.at(0) + .4).usec # => 400000

Smells like floating point arithmetic in action to me … try

[0.1, 0.2, 0.3, 0.4, 0.5].each { |f|
puts ‘%.20f’ % f
}

Hi,

This is not the whole story IMHO. You have to take rounding issues in
account. If ruby rounded the value to full microseconds in the usual way,
you would see 300000 instead of 299999. The precision of a double is still
just enough to discriminate full microseconds in a date (when zero is
1970/1/1 and proper rounding is applied).

Currently rounding isn’t applied.

I don’t know for sure, but I suspect that ruby is always rounding down
dates and times by intention – otherwise, what would happen to

Time.utc(1970,12,31,23,59,59,999999) + .9e-6

Rounding up the microseconds value may also alter everything else in the
date, including the year. Would you want that?

Is it correct? 23:59:59.9999999 is next day?

Anyway, following is rounding patch, but why round() doesn’t
work on my box?

Index: time.c

···

At Mon, 16 Sep 2002 19:30:33 +0900, Tobias Peters wrote:

RCS file: /cvs/ruby/src/ruby/time.c,v
retrieving revision 1.68
diff -u -2 -p -r1.68 time.c
— time.c 8 Sep 2002 12:59:07 -0000 1.68
+++ time.c 16 Sep 2002 14:34:19 -0000
@@ -969,5 +969,5 @@ time_plus(time1, time2)
}
#endif

  • usec = tobj->tv.tv_usec + (time_t)(d*1e6);
  • usec = (time_t)(tobj->tv.tv_usec + d*1e6 + 0.5);
    sec = tobj->tv.tv_sec + (time_t)f;

@@ -1016,5 +1016,5 @@ time_minus(time1, time2)
}
#endif

  • usec = tobj->tv.tv_usec - (time_t)(d*1e6);
  • usec = (time_t)(tobj->tv.tv_usec - d*1e6 + 0.5);
    sec = tobj->tv.tv_sec - (time_t)f;
    #ifdef NEGATIVE_TIME_T


Nobu Nakada