6

Why does adding 6.1000000 seconds to a DateObject display as having added 6.099?

Mathematica notebook picture

If I copy the Out[20] element from this picture, it contains the correct value:

DateObject[{2014, 11, 7}, TimeObject[{8, 0, 6.1}], CalendarType -> "Gregorian"]

...but why does it display as 6.099 instead of 6.100?

More to the point, how can I make it display the correct answer?

Sektor
  • 3,320
  • 7
  • 27
  • 36
Cary Millsap
  • 173
  • 5

3 Answers3

3

This is the only 'fix' I could find.

Initialize the following:

$DateStringFormat = {"Year", "-", "Month", "-", "Day", "T", "Hour", ":", "Minute", ":", "SecondExact"};

System`DateStringDump`convertDateStringForms[{__, s_}, _, _, "Millisecond"] := 
  ToString[Floor[1000000 Round[FractionalPart[s], .00001]]]

Run your command:

DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.100000, "Second"]

enter image description here

Greg Hurst
  • 35,921
  • 1
  • 90
  • 136
  • 1
    Why not define a custom format: SystemDateStringDumpconvertDateStringForms[{__, s_}, _, _, "mysecpart"] := ToString[Floor[1000000 Round[FractionalPart[s], .00001]]] and then $DateStringFormat = {"Year", "-", "Month", "-", "Day", "T", "Hour", ":", "Minute", ":", "Second", ".", "mysecpart"}. – Michael E2 Nov 07 '14 at 23:36
  • 1
    Or do the seconds directly: SystemDateStringDumpconvertDateStringForms[{__, s_}, _, _, "mysec"] := StringDrop[ToString@NumberForm[6.1, {8, 6}, NumberPadding -> {"0", "0"}], 1]. Not sure why M won't pad in the way everybody wants (i.e., StringDrop should be unnecessary). – Michael E2 Nov 07 '14 at 23:52
  • Chip, I used $DateStringFormat = {"Year", "-", "Month", "-", "Day", "T", "Hour", ":", "Minute", ":", "SecondExact"} SystemDateStringDumpconvertDateStringForms[{__, s_}, _, _, "Millisecond"] := ToString[Floor[1000000 Round[FractionalPart[s], .00001]]] DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.100000, "Second"] DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.0000101, "Second"], which worked great for the 6.100000 example, but it renders 6.0000101 as 6.10. ?? – Cary Millsap Nov 08 '14 at 00:26
  • I was wrong in my previous comment. It's going to be easier to explain with a picture. What is the appropriate way for me to do that? – Cary Millsap Nov 08 '14 at 00:51
1

This boils down to floating point error.

In binary, 0.1 does not have a finite decimal expansion, so your computer must round.

This is a problem at a hardware level and can only be fixed by setting a precision higher than machine precision.

Here is what the fractional part of your float really looks like:

FractionalPart[6.1] // FullForm
(* 0.09999999999999964` *)

Here is what the fractional part of a higher precision number looks like:

FractionalPart[6.1`20] // FullForm
(* 0.1`18.214670164989236 *)

(The number after the ` is the precision)

Greg Hurst
  • 35,921
  • 1
  • 90
  • 136
  • 1
    Chip, thank you very much. How can I make it render as ".1"; actually, I'd like it to render as ".100000". ...Another problem I have is that all my work is in microseconds. – Cary Millsap Nov 07 '14 at 21:37
1

Here is the answer that, with @Chip's and @Michael's help, I came to:

$DateStringFormat = {"Year", "-", "Month", "-", "Day", " ", "Hour", ":", "Minute", ":", "Second", ".", "Foo"};
System`DateStringDump`convertDateStringForms[{__, s_}, _, _, "Foo"] := Module[{n = 6}, StringTake[ToString[PaddedForm[N[Round[s, 10^-n]], {30, n}]], -n]];
DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.100000, "Second"]
DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.0000107, "Second"]
DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.0000108, "Second"]
DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.12345671, "Second"]
DateObject[{2014, 11, 7, 8, 0, 0}] + Quantity[6.12345672, "Second"]

Still, two things bother me: (1) I can't find documentation about "DateStringDump" in the Mathematica documentation, or anywhere on Google! (2) Why does Round[_,10^-6] yield .0000107→.000010 and .0000108→.000011; and why .12345671→.123456 and .12345672→.123457? I see no pattern here. ...Maddening.

Cary Millsap
  • 173
  • 5
  • (1) There is a name for those sorts of commands: "undocumented". :) (2) I get 0.0000107 → 0.000011. – Michael E2 Nov 10 '14 at 22:03
  • @MichaelE2, understood on point 1, although I'm curious where someone learns of its existence. On point 2, I do too, when I use PaddedForm[N[Round[{6.0000104, 6.0000105, 6.0000106, 6.0000107}, 10^-6]], {10,6}] ...but not when I use the code shown above. – Cary Millsap Nov 10 '14 at 22:52
  • 1
    A few ways: ?*`*key* etc., foo = Trace[expr, TraceInternal -> True]; (loads of output consisting of evaluation chains, which takes some patience and strategy to find the important bit), LinkSnooper, and some of the contributors here work at Wolfram and just know things. There is also guessing, which works sometimes because Mathematica has a certain "style." In fact, I guessed at my comment to Chip Hurst's answer, checked it out, and what do you know, it worked. – Michael E2 Nov 11 '14 at 00:09
  • And I forgot this one: http://mathematica.stackexchange.com/questions/1742/what-is-the-most-convenient-way-to-read-definitions-of-in-memory-symbols-when-we – Michael E2 Nov 12 '14 at 17:17
  • @CaryMillsap It looks like there is rounding errors that I alluded to in one of my answers when adding the DateObject and the Quantity. One way around that is to do DateObject[{2014, 11, 7, 8, 0, 6.0000107}]. – Greg Hurst Nov 14 '14 at 16:12