October 30, 2019
On Wednesday, 30 October 2019 at 19:28:27 UTC, Ali Çehreli wrote:
> Just to make sure, you are aware of the optional '-' before '(', right? "%-(%s%)" does not print the quotes.

I know this. I personally think, it is somewhat ugly, but I understand how it came to have it like this. My rationale is more like this: Currently it probably won't be possible to change the behavior of %s, because that would be a code breaking change. But there might be a time in the future, where it's possible to do some code breaking changes, maybe when D2 -> D2.1 or something like this. It will be much easier to do these changes at that time, when there is a well tested, simple and working alternative that can be pointed out to the users. Therefore it's a good idea to implement this alternative right now. Isn't it?
October 30, 2019
On Wednesday, 30 October 2019 at 19:19:06 UTC, berni44 wrote:
> On Wednesday, 30 October 2019 at 17:50:03 UTC, Jon Degenhardt wrote:
>> It's reasonably common to have numeric values written out in text format and read back in and used in subsequent computations. Not always a great idea, especially when done without much consideration for round-off errors. But it's not uncommon.
>
> But IMHO this is the fault of people who do this and not the fault of a printing routine.

You are correct, but people will still blame the printing routine.
October 30, 2019
On Wednesday, 30 October 2019 at 19:28:44 UTC, berni44 wrote:
> On Wednesday, 30 October 2019 at 18:16:56 UTC, Rumbu wrote:
>> That means that snprintf must use the current rounding mode that can be read using FloatingPointControl.rounding from std.math.
>
> Is it really a "must"? We are not completely bound by the IEEE standard and, if good reasons are available, might reject it. For example, comparing two floats with <= produces either "false" or "true" in D. According to IEEE there should be a third result possible, namly "not comparable". Having said this, it would be possible to implement it the way you claim, but probably at some cost (=slower, more and less easy readable lines of code). I'll think about it.

I don't know the inners of your code, but I suppose that before "printing" you end up with an integer value and a ten-based exponent.

In this case rounding becomes a question of how do you interpret the remainder of a division by a power of ten.

Because I spent a lot of time figuring out how  to format correctly decimal numbers, here is some piece of code I use in order to format decimal numbers depending on the rounding mode, fully compliant with the standard.

https://github.com/rumbu13/decimal/blob/a6bae32d75d56be16e82d37af0c8e4a7c08e318a/src/decimal/decimal.d#L7296

Hope this helps.




October 30, 2019
On Wednesday, 30 October 2019 at 13:44:52 UTC, berni44 wrote:
> In PR 7222 [1] Robert Schadek suggested replacing the call to snprinf in std.format with an own method written in D. During the last days I took a deeper look into this and meanwhile I've got a function that works for floats

If you could post that so I can have a look over the WIP that'd be nice.

Grisu2 also uses lookup tables, though for 52bit mantissa floats it's completely fine.
October 30, 2019
On Wed, Oct 30, 2019 at 07:28:44PM +0000, berni44 via Digitalmars-d wrote:
> On Wednesday, 30 October 2019 at 18:16:56 UTC, Rumbu wrote:
> > That means that snprintf must use the current rounding mode that can be read using FloatingPointControl.rounding from std.math.
> 
> Is it really a "must"? We are not completely bound by the IEEE standard and, if good reasons are available, might reject it. For example, comparing two floats with <= produces either "false" or "true" in D. According to IEEE there should be a third result possible, namly "not comparable".

For non-comparable floats x and y (i.e., at least one is a NaN), D has
the semantics:

	x < y		false
	x <= y		false
	x >= y		false
	x > y		false
	x == y		false
	x != y		true

D used to have other comparison operators that handle various NaN-related subtleties (the so-called "spaceship operators" because of their alien appearance), but they were deprecated because nobody understood them so nobody used them.

Having said that, though, I think we should try to conform to IEEE as much as possible, and there better be very good reasons when we don't.


> Having said this, it would be possible to implement it the way you claim, but probably at some cost (=slower, more and less easy readable lines of code). I'll think about it.

As I have said, floating-point formatting is far from the trivial affair that it appears to be on the surface.  It's not something to be undertaken lightly, because it's full of complicated corner cases that must be handled correctly.


T

-- 
Never wrestle a pig. You both get covered in mud, and the pig likes it.
October 30, 2019
On Wed, Oct 30, 2019 at 07:11:14PM +0000, berni44 via Digitalmars-d wrote:
> On Wednesday, 30 October 2019 at 17:41:26 UTC, H. S. Teoh wrote:
[...]
> > Formatting floating-point numbers is not a trivial task. It's easy to write up something that works for common cases, but it's not so easy to get something to gives the best results in *all* cases.
> 
> I know, that this is something we all wish. Anyway, my goal is set somewhat lower: I'd like to replace the existing call to snprintf with something that is programmed in D and which should be pure, @safe and ctfeable. And ideally it should not be slower then snprintf.

Yeah, I've been waiting for a long time for a pure, @safe, and CTFE-able floating point formatter in D.  What rumbu said about rounding mode, though, makes me fear that pure may not be attainable if we're going to be IEEE-compliant (since accessing the current rounding mode would be technically impure).

Then again, the CTFE-able version can probably be made pure, since CTFE cannot change rounding mode in the compiler's runtime environment, so if we detect CTFE then we can just assume the default rounding mode.

	auto formatFloat(F)(F f) {
		FloatingPointControl fc;
		if (__ctfe)
			return formatFloatImpl(fc.roundToNearest); // pure
		else
			return formatFloatImpl(fc.rounding); // impure
	}

should do it.


> > You probably should use the algorithms referenced above for your implementation,
> 
> I read through the paper for the ryu algorithm and rejected it (at least for me; if someone else is goint to implement it and file a PR that's fine). My reason for rejecting is, that the algorithm has not exactly the same goal as printf, which IMHO means, that it cannot be used here; and that it needs a lookuptable, that is too large (300K for 128bit reals).

Why is it too large?  Couldn't you generate the table with CTFE? :-D

Or statically generate it and then import it, like std.uni does with the various Unicode tables (see std.internal.unicode_*).


[...]
> Obviously I need to prove, that the algorithm is correct somehow. While this can be done for floats by running it on all numbers and comparing these results with the result of snprintf (or the result calculated by bc), for doubles and reals, this isn't possible anymore (a random sample can be tested anyway, but that's no proof).

Are we just copying whatever snprintf does? Is snprintf really a reliable standard to go by?


> Anyway, I think, that the proof isn't hard to give. The current algorithm is short and straight forward. (And: When I implement one of the mentioned algorithms, it can still contain bugs, because I made a mistake somewhere.)

You don't necessarily have to implement grisu, et al, verbatim, but your algorithm should at least gracefully handle the special cases and potentially problematic cases cited in the papers.


T

-- 
Too many people have open minds but closed eyes.
October 30, 2019
Replacing snprintf for floating point is very challenging, because:

1. people have been improving snprintf for decades
2. people expect precision and performance
3. the standard is snprintf, any credible implementation must be the same or better

To that end, you'll need to be familiar with the following:

754-2019 IEEE Standard for Floating Point Arithmetic
https://ieeexplore.ieee.org/document/8766229

Printing Floating-Pointer Numbers Quickly and Accurately with Integers
https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf

Printing Floating-Point Numbers
https://ranjitjhala.github.io/static/fp-printing-popl16.pdf

Ryu Fast Float To String Conversion
https://dl.acm.org/citation.cfm?id=3192369

https://github.com/ulfjack/ryu
http://www.zverovich.net/2019/02/11/formatting-floating-point-numbers.html
https://news.ycombinator.com/item?id=20181832

Jonathan Marler's D implementation of ryu:
https://github.com/dragon-lang/mar/blob/master/src/mar/ryu.d

For historical interest, here's DMC's version, which was state of the art in the 1980's:

https://github.com/DigitalMars/dmc/blob/master/src/core/floatcvt.c
October 31, 2019
On 10/30/19 10:54 PM, Sebastiaan Koppe wrote:
> On Wednesday, 30 October 2019 at 19:19:06 UTC, berni44 wrote:
>> On Wednesday, 30 October 2019 at 17:50:03 UTC, Jon Degenhardt wrote:
>>> It's reasonably common to have numeric values written out in text format and read back in and used in subsequent computations. Not always a great idea, especially when done without much consideration for round-off errors. But it's not uncommon.
>>
>> But IMHO this is the fault of people who do this and not the fault of a printing routine.
> 
> You are correct, but people will still blame the printing routine.

I wouldn't state it is any fault. In some cases it is much more productive to have text representation of data than binary ones. Initially I believed too that binary representation is the more suitable but afterwards I  was forced to use text format and that gives me a good result.
October 31, 2019
On Wednesday, 30 October 2019 at 13:44:52 UTC, berni44 wrote:
> In PR 7222 [1] Robert Schadek suggested replacing the call to snprinf in std.format with an own method written in D.

I suggested it because formatImpl!float is not pure which makes for instance
std.json not pure among a few other.
October 31, 2019
On Thursday, 31 October 2019 at 01:09:14 UTC, Walter Bright wrote:
> Replacing snprintf for floating point is very challenging, because:
>
> 1. people have been improving snprintf for decades
> 2. people expect precision and performance
> 3. the standard is snprintf, any credible implementation must be the same or better
>


Moreover, actual printf implementations seems to depend upon the locale. This creates bugs (say "1,4" instead of "1.4") so this behaviour depends if you want to be bug-compatible. We've been hit by that in `printed` when used with a Russian locale.