Jump to page: 1 24  
Page
Thread overview
[Issue 6725] core.time.dur should accept floating point
Jul 21, 2014
Vladimir Panteleev
Jul 21, 2014
Jonathan M Davis
Jul 21, 2014
Jonathan M Davis
Jul 21, 2014
Vladimir Panteleev
Jul 21, 2014
Jonathan M Davis
Jul 21, 2014
Vladimir Panteleev
Jul 21, 2014
Jonathan M Davis
Jul 21, 2014
Vladimir Panteleev
Jul 21, 2014
Jonathan M Davis
Jul 21, 2014
Vladimir Panteleev
Jul 21, 2014
Jonathan M Davis
Jul 21, 2014
Vladimir Panteleev
Jul 21, 2014
Jonathan M Davis
Jul 23, 2014
Sobirari Muhomori
Jul 23, 2014
Vladimir Panteleev
Jul 23, 2014
Jonathan M Davis
Jul 23, 2014
Jonathan M Davis
Jul 23, 2014
Jonathan M Davis
Jul 23, 2014
Jonathan M Davis
Jul 23, 2014
Sobirari Muhomori
Jul 23, 2014
yebblies
Jul 23, 2014
Vladimir Panteleev
Jul 24, 2014
Walter Bright
Jul 24, 2014
Walter Bright
Jul 24, 2014
Sobirari Muhomori
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

Vladimir Panteleev <thecybershadow@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |thecybershadow@gmail.com
         Resolution|WONTFIX                     |DUPLICATE

--- Comment #7 from Vladimir Panteleev <thecybershadow@gmail.com> ---
Considering how difficult it is to convert an FP value to a Duration, I definitely think that this behavior belongs in the standard library.

https://github.com/D-Programming-Language/druntime/pull/905

(In reply to Walter Bright from comment #6)
> 1. Using floating point for time is like using floating point for accounting software ($57.23). It doesn't work for things that come in discrete quanta (pennies, clock ticks). You will spend FAR more time chasing weird problems than you will save in "convenience". Yes, I have experience with this, and I understand floating point (having build FP emulators).

This argument is exaggerated. Not all measurements of time need to be precise. For example, if an utility program could accept a timeout value from the user, it's more useful to allow them to specify a fractional value.

> 2. Many machines have very poor FP performance compared with integer performance. Implementing basic operations using unnecessary FP results in slow, bloated code.

FP code will only work when the user passes FP values to Druntime functions. It does not affect existing code. I don't see how this argument applies.

> 3. Phobos' time functions are already massively complex. I still can't even compile the datetime unittests on a 512Mb machine. Please, no more.

"dur" is in Druntime (core.time), not Phobos. I have created a patch already, and it is rather simple.

> 4. It's trivial for a user to write their own FP wrapper around dur.

I disagree, it is not trivial.

> There is no reason to integrate this into dur itself.

I disagree, it is a useful addition that I wished a few times would be there.

> Software should be pieced together using layers of abstraction, not kitchen sink base types.

I don't see how this applies here. Making the functions generic does add more abstraction.

> 5. It would take longer to read the documentation for this enhancement than to just convert your floating point value to an int.

I believe that's objectively wrong.

> 6. You're not forced to write long complicated expressions to convert fp to integers. It's just a scale and a cast:
> 
>     dur!("secs")(1.5001) => dur!("nsecs")(cast(long)(1.5001 * 1000000));

I think this is a bad solution because:

1. It does not operate on the actual resolution of Duration, which is hnsecs. Forcing the user to move that up to their user code would imply a leaky abstraction.

2. Did he type 6 zeroes, or only 5? It's forcing the use of magic numbers. The
non-magic-number expression has already been posted here (`convert!("seconds",
"hnsecs")(1)`), but it makes the expression even bulkier.

3. It's duplicating logic which already exists in core.time. Opening up the existing conversion code to accept FP values was trivial - the existing algorithms takes care of FP values just fine.

*** This issue has been marked as a duplicate of issue 13176 ***

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

Steven Schveighoffer <schveiguy@yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy@yahoo.com

--- Comment #8 from Steven Schveighoffer <schveiguy@yahoo.com> ---
I feel like I should weigh in on this.

While I agree it's not good to deal with floating point at a low level (Duration should never contain a floating point value), *creating* a duration based on a floating point is OK as long as the conversion is sound. Note that the most common usage of this would be for Duration literals.

IIRC, you can guarantee the conversion is sound by using an epsilon. In other words, if you pass in 1.5, it's really 1 second, 500 milliseconds, not 1.4999999... seconds.

I agree with Vladimir's point, even if there is some error in floating point representation, sleeping e.g. for 1.499 seconds vs. 1.5 isn't going to make a large difference. But I think we can largely avoid the floating point error.

Where things become dicey is when you are accumulating lots of floating point values, or if you are working with very very small values.

Note, the indicated mechanism to make a proper duration has improved somewhat:

1.second + 500.msecs + 100.usecs;

I think this still looks awful.

As a compromise, one could make a text-parser based mechanism, similar to octal:

dur!"1.5001s"();

That translates into the above.
Not sure how well this would turn out ;)

A true "literal" syntax would make things easier to deal with.

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #9 from Jonathan M Davis <jmdavisProg@gmx.com> ---
(In reply to Steven Schveighoffer from comment #8)
> Note, the indicated mechanism to make a proper duration has improved somewhat:
> 
> 1.second + 500.msecs + 100.usecs;
> 
> I think this still looks awful.

In most cases, the most that you'd need would be two pieces, not three. And I think that that's a small price to pay for avoiding floating point errors.

> As a compromise, one could make a text-parser based mechanism, similar to octal:
> 
> dur!"1.5001s"();
> 
> That translates into the above.
> Not sure how well this would turn out ;)
> 
> A true "literal" syntax would make things easier to deal with.

So, basically, you're suggesting that we create function or template which takes a string which represents a floating point value at compile time and generates a Duration from that, erroring out if it doesn't convert properly to hnsecs? That would be pretty easy to do (though I wouldn't reuse dur for that, since it already has a string template parameter - maybe durLit), and it would avoid the problem with floating point error. Any floating point string with no more than 7 decimal places (since that's what hnsecs will give you) and which wasn't too large for a long to hold once converted would convert just fine without floating point errors. That would certainly be better than allowing floating point values at runtime.

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #10 from Steven Schveighoffer <schveiguy@yahoo.com> ---
(In reply to Jonathan M Davis from comment #9)
> (In reply to Steven Schveighoffer from comment #8)
> > Note, the indicated mechanism to make a proper duration has improved somewhat:
> > 
> > 1.second + 500.msecs + 100.usecs;
> > 
> > I think this still looks awful.
> 
> In most cases, the most that you'd need would be two pieces, not three. And I think that that's a small price to pay for avoiding floating point errors.
> 

I was just going by the example you gave. You could do it in 2 pieces, but then you start getting into much larger numbers:

1.second + 500100.usecs;

But I think there is a over-concern here about floating point conversion. It can be made to be exact, as long as you are dealing with literals. I remember running an extensive test back when I was working on the Tango time code. All you have to do is add an epsilon of .5 hnsecs or something like that.

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #11 from Jonathan M Davis <jmdavisProg@gmx.com> ---
(In reply to Steven Schveighoffer from comment #10)
> I was just going by the example you gave. You could do it in 2 pieces, but then you start getting into much larger numbers:
> 
> 1.second + 500100.usecs;

Yeah. I was just trying to point out that in practice, you pretty much would just need some number of seconds and the fractional seconds would then probably just be multiple of 10 of either msecs or usecs. Having to do something like 1.5001 is not likely to be common at all, so if it's a bit uglier, oh well.

> But I think there is a over-concern here about floating point conversion. It can be made to be exact, as long as you are dealing with literals. I remember running an extensive test back when I was working on the Tango time code. All you have to do is add an epsilon of .5 hnsecs or something like that.

I'm not opposed to something like durLit!("1.2552", "seconds") which is then essentially a Duration literal which can be a floating point value. However, using floating point values for time at runtime is just begging for bugs, and such code should be avoided with extreme prejudice.

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #12 from Vladimir Panteleev <thecybershadow@gmail.com> ---
I'd just like to point out that there are more uses to FP time values than literals, such as user input. A template which accepts a string as a compile-time parameter solves none of my personal use-cases.

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #13 from Jonathan M Davis <jmdavisProg@gmx.com> ---
(In reply to Vladimir Panteleev from comment #12)
> I'd just like to point out that there are more uses to FP time values than literals, such as user input. A template which accepts a string as a compile-time parameter solves none of my personal use-cases.

If user input is the issue, a function which took a string which represented the time as a floating point and parsed it to a Duration would presumably do the trick while avoiding the floating point errors and without encouraging using floating point values for time in general. It would work well for user input (because it would already be a string) while being a royal pain for anyone who wanted to use floating point values for time directly, because they'd be forced to convert the floating point value to a string in order to then use the function to convert it to a Duration.

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #14 from Vladimir Panteleev <thecybershadow@gmail.com> ---
> while being a royal pain for anyone who wanted to use floating point values for time directly

I think that's objectively false: just add `.text`

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #15 from Steven Schveighoffer <schveiguy@yahoo.com> ---
(In reply to Jonathan M Davis from comment #11)
> 
> I'm not opposed to something like durLit!("1.2552", "seconds") which is then essentially a Duration literal which can be a floating point value. However, using floating point values for time at runtime is just begging for bugs, and such code should be avoided with extreme prejudice.

I don't agree with that. It depends on the purpose of the duration value. Note that Objective-C uses Interval to represent all durations, and it is a typedef of double. I have not had any adverse experience with it.

(In reply to Vladimir Panteleev from comment #12)
> I'd just like to point out that there are more uses to FP time values than literals, such as user input. A template which accepts a string as a compile-time parameter solves none of my personal use-cases.

Such a template can be built from a CTFE-able function, which would be available at runtime as well.

--
July 21, 2014
https://issues.dlang.org/show_bug.cgi?id=6725

--- Comment #16 from Jonathan M Davis <jmdavisProg@gmx.com> ---
(In reply to Steven Schveighoffer from comment #15)
> (In reply to Jonathan M Davis from comment #11)
> > 
> > I'm not opposed to something like durLit!("1.2552", "seconds") which is then essentially a Duration literal which can be a floating point value. However, using floating point values for time at runtime is just begging for bugs, and such code should be avoided with extreme prejudice.
> 
> I don't agree with that. It depends on the purpose of the duration value. Note that Objective-C uses Interval to represent all durations, and it is a typedef of double. I have not had any adverse experience with it.

Every application that I've seen use doubles for time has had bugs because of it. It works in a lot of cases, but you end up with subtle problems as a result. Durations aren't as bad as timestamps, but it's still asking for trouble. It's just far better IMHO to avoid the floating point values entirely and not have to deal with those bugs, especially because using floating point values generally doesn't buy you much.

(In reply to Vladimir Panteleev from comment #14)
> > while being a royal pain for anyone who wanted to use floating point values for time directly
> 
> I think that's objectively false: just add `.text`

Would you honestly expect folks to be using to!string or text to convert floating point values to Durations in their code on a regular basis? Sure, someone might do it, but it's an extra layer of ugly and a performance hit to do so. It doesn't _stop_ anyone from doing it, but it makes it hard enough and ugly enough that I'd expect most people not to do it.

With something like dur!"seconds"("1.5") or seconds("1.5"), the folks who want literals are fine, as is anyone getting user input, but we avoid directly supporting folks using floating point values for durations, and we avoid floating point errors with regards to literals or user input, whereas using actual floating point values risks floating point errors.

--
« First   ‹ Prev
1 2 3 4