std::cout << std::to_string(1e-9); // output: "0.000000"
std::cout << std::to_string(6.67408e-11); // output: "0.000000"
std::cout << std::to_string(6.626070040e-34) // output: "0.000000"
std::cout << std::to_string(1.23e100); // output:
"1229999999999999945619502435678791882061496502770990950045684429327960298864608335541984218516600989160291306221939122973741400364055485571676274743695192965637069768948118175959863951770799435358111025735195134313314113829815221797071926323389168215764573082356023275727273837119288529943287157489664.000000"
std::cout << std::to_string(1.23e-300); // output:"0.000000"
std::cout << 1.23e300; // " output: "1.23e+300"
std::cout << 1.23e-300; // " output: "1.23e-300"
std::cout << 1e-9; // output: "1e-09"
std::cout << std::to_string(1e-9); // output: "0.000000"
#include <iostream>
#include <string>
int main()
{
std::cout << std::to_string(1e-9) << '\n';
std::cout << std::to_string(6.67408e-11) << '\n';
std::cout << std::to_string(6.626070040e-34) << '\n';
std::cout << std::to_string(1.23e300) << '\n';
std::cout << std::to_string(1.23e-300) << '\n';
std::cout << 1.23e300 << '\n';
std::cout << 1.23e-300 << '\n';
std::cout << 1e-9 << '\n';
std::cout << std::to_string(1e-9) << '\n';
return 0;
}
Even if you set formatting flags correctly
(i.e. infinite width and precision, locale-agnostic formatting, etc.),
the formatting and parsing process itself may introduce error. Then
there are denormal FP values, which may or may not be rounded to zero
during any arithmetic operations that are applied during formatting and
parsing.
> Examples:
> 1.
> |
> std::cout <<std::to_string(1e-9);// output: "0.000000"
> std::cout <<std::to_string(6.67408e-11);// output: "0.000000"
> std::cout <<std::to_string(6.626070040e-34)// output: "0.000000"
> |
>
> All values are certainly different but their string representations are
> identical. As such to_string() essentially wipes out the numeric
> information. It's also worth noting that the resulting string may even
> be longer than a valid and likely the most natural string presentation
> (e.g. "1e-9") even though to_string() has destroyed the information.
Again, the standard defines the format of the strings and it does not
allow for "1e-9" output. It does not make the function work incorrectly
or not useful. Personally, I do find the std::fixed style more readable,
even though it leads to information loss like in the above. That makes
to_string more useful for diagnostic purposes to me.
On 2015-11-09 04:17, Nicol Bolas wrote:
>
>
> On Sunday, November 8, 2015 at 4:54:13 PM UTC-5, Andrey Semashev wrote:
>
> I'd say every design that relies on FP<->string<->FP to be a lossless
> roundtrip is likely broken, whether it employs to_string/stod or
> iostreams or C equivalents.
>
>
> I suggest you take that up with pretty much every user of Collada or
> similar text-based technologies. Whatever your personal feelings on the
> matter may be, the facts on the ground are that round-tripping is
> /important/ to many users.
I'm not sure what exactly I have to take to those users. I don't think
the problems I'm pointing out will be a surprise for them.
> How about round-tripping that isn't ridiculously broken? It's one thing
> to have a value that loses a couple of digits of precision. It's quite
> another to lose /the entire value/.
No, it's really not.
A loss is a loss, only with %f you have a constant
factor of error
and in case of %g you get error that depends on the
value itself.
There will always be the case when the representation
looses more than you're willing to accept.
> We don't need the round trip to guarantee perfect precision
> reproduction. But that's no excuse for not /improving/ what we have.
I didn't say I'm against progress. :) What kind of improvement do you
have in mind?
> How useful that is for "diagnostic purposes" rather depends on what you
> are diagnosing, don't you think? I've been in situations in graphics
> work where getting only 2 digits of precision in text is not even close
> to acceptable even as a diagnostic.
Fair enough. If you're dealing with numbers that tend to be very large
or very small, applying %f directly may be suboptimal. Thing is, %g is
also not a very good choice because this format is difficult to
comprehend. Can you immediately tell if 1.23847623e10 is greater than
1.23843754e11?
I'd say an improved format would be a %g with a fixed
user-definable e so that the two numbers could be presented as
1.23847623e10 and 12.3843754e10.
> It is far worse than outputting 0.000001 when I gave it
> 0.0000008.
So is the problem in the rounding mode? What if the number is 0.0000001,
is it allowed to be formatted as 0.000000?
> A loss is a loss, only with %f you have a constant
> factor of error
>
>
> I'm not sure what you mean by "factor of error". The amount of error you
> lose with `%f` is certainly not constant with respect to the size of the
> number. If you output 1234500.0f, you will lose no digits of precision.
> If you output `0.00012345`, you will lose two decimal digits of precision.
>
> That's not "constant".
Maybe my wording was poor; English is not my native language, sorry.
What I mean is that whatever number you format with %f you will get a
fixed precision up to 6-th digit after the decimal point.
You lose
anything more precise than that. In other words, the represented number
is N±1e-6, and the representation error is constant. That is not the
case with %g, which only keeps a fixed portion of the most significant
digits and looses the rest (thus the amount of error depends on the number).
> Consider instead 0.000000 and 0.000000. Can you tell which is bigger?
> /Nobody/ can, no matter how long you look at it.
I can - the numbers are equal.
And yes, this outcome, while probably is
surprising to some, is perfectly logical. The same way '(int)1.2 ==
(int)1.3' holds true because you're comparing not the doubles but ints.
> Comprehension may take longer with %g, but it is at least /possible/.
You will have the same kind of problem with %g if you compare formatted
numbers 1e50+1 and 1e50.
On Sun, Nov 8, 2015 at 10:54 PM, Andrey Semashev <andrey....@gmail.com> wrote:[...]> I'd say every design that relies on FP<->string<->FP to be a lossless roundtrip is likely broken, whether it employs to_string/stod or iostreams or C equivalents.Given that just about every floating point unit in the world operates in accordance with IEEE 754 [1], there is no good excuse for not having a standardized textual representation of floating point numbers that is loseless. At the very least, the C++ standard could require an implementation-defined format that is loseless when used within that particular implementation.
On Monday, November 9, 2015 at 9:59:45 AM UTC-5, Viacheslav Usov wrote:On Sun, Nov 8, 2015 at 10:54 PM, Andrey Semashev <andrey....@gmail.com> wrote:[...]> I'd say every design that relies on FP<->string<->FP to be a lossless roundtrip is likely broken, whether it employs to_string/stod or iostreams or C equivalents.Given that just about every floating point unit in the world operates in accordance with IEEE 754 [1], there is no good excuse for not having a standardized textual representation of floating point numbers that is loseless. At the very least, the C++ standard could require an implementation-defined format that is loseless when used within that particular implementation.
No, it is not.
It is not possible to convert every binary IEEE-754 representable number into a decimal version that will convert back to exactly that float. Just as there are many decimal float numbers that do not convert into an exact binary IEEE-754 number.
On Mon, Nov 9, 2015 at 4:09 PM, Nicol Bolas <jmck...@gmail.com> wrote:> It is not possible to convert every binary IEEE-754 representable number into a decimal version that will convert back to exactly that float.You are disputing a statement that I never made.> And that's not what we're talking about.You are mistaken, because we are very obviously talking about that.
> We're asking for not-stupidity, not losing precision for arbitrary reasons.Base 10 is entirely arbitrary.
print(0.000000001)
1e-9
print(0.000000001)
1e-9
using System;
public class Test
{
public static void Main()
{
// your code goes here
Console.WriteLine("{0}", 0.000000001);
}
}
1e-9
import java.io.*;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
System.out.println(Float.toString(0.000000001f));
}
}
1e-9
#include <iostream>
#include <string>
using namespace std;
int main() {
cout << to_string(0.000000001f) << "\n";
return 0;
}
0.000000
> > Comprehension may take longer with %g, but it is at least
> /possible/.
>
> You will have the same kind of problem with %g if you compare formatted
> numbers 1e50+1 and 1e50.
>
>
> But that's only because you broke floating-point precision. Within the
> boundaries of floating point precision, %g will print the right answer.
Sorry, I miscalculated the numbers.
#include <cstdio>
#include <iostream>
int main()
{
char buffer[32];
sprintf(buffer, "%f", 123.3);
std::cout << buffer << '\n';
sprintf(buffer, "%g", 123.3);
std::cout << buffer << '\n';
sprintf(buffer, "%.16g", 123.3);
std::cout << buffer << '\n';
sprintf(buffer, "%.19g", 123.3);
std::cout << buffer << '\n';
double n1 = (1e15) + 1.0;
double n2 = 1e15;
std::printf("%.19g\n%.19g", n1, n2);
}
Output
123.300000
123.3
123.3
123.2999999999999972
1000000000000001
1000000000000000
Again, since at least Steele's paper it is know how to give out strings which reads back as the original yet are not surprising to the user. I'd not be surprised if Scheme or Java mandated their use BTW. And IIRC Lawrence Crawl hinted in the numeric group that he wanted to have such thing normalized as well, I don't remember having seen a paper.
On Monday 09 November 2015 15:59:43 Viacheslav Usov wrote:
> Given that just about every floating point unit in the world operates in
> accordance with IEEE 754 [1], there is no good excuse for not having a
> standardized textual representation of floating point numbers that is
> loseless.
Yes, there is. See these bug reports about using a too-precise number:
On Mon, Nov 9, 2015 at 4:53 PM, Nicol Bolas <jmck...@gmail.com> wrote:
> That's what people know, so that's what `to_string` ought to output.People know a few other things, too. Feel free to apply your reasoning to this premise.The need to represent floating point literals in C++ exactly is different from the need to represent floating point numbers as taught by the world's school system.
And by the way, the subject of this thread is about deprecating to_string, so to_string can happily continue losing precision.
On Monday 09 November 2015 12:04:30 Andrey Semashev wrote:
> Thing is, %g is
> also not a very good choice because this format is difficult
And %g is also insufficient. You want %.19g so that you have enough digits to
make the round-trip conversion lossless.
Then you'll get bug reports from your users that you're writing too many
digits and that some imprecise FP numbers like 1.3 are actually shown as a
very long number close to 1.3 but different from it (same FP number though).
This is not a wild prediction on my part. It has already happened. I changed
the QVariant conversion of double to string to %.19g and we got several bug
reports about the too-precise number. Our conclusion: we'll import a whole new
library into QtCore that is better at converting doubles to string than
snprintf.