Thread overview  


October 08 formatting a float or double in a string with all significant digits kept  

 
I have a double precision number that i would like to print all significant digits of, but no more than what are actually present in the number. Or more exactly, i want to print the minimum number of digits necessary to recover the original number to within 2 or 3 least significant bits in the stored, incore, version of its bit pattern. For example, import std.string; import std.stdio; import std.math; void main( ) { auto t = format("%3.30f", PI ); writeln("Value of PI is: ", PI, " or, : ", t); } The default way writeln prints is 5 digits to the right of the decimal point. I can format to print with any number of digits, such as 30 above, but that's too many. For pi, the correct number of digits to print looks to be about 18 (and the extra 12 digits presumably are from the decimal expansion of the least significant bit?). But i would like to be able to do this without knowing the expansion of pi, or writing too much code, especially if there's some d function like writeAllDigits or something similar. Thanks in advance for any pointers! dan 
October 09 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to dan  On Tuesday, 8 October 2019 at 20:37:03 UTC, dan wrote: > But i would like to be able to do this without knowing the expansion of pi, or writing too much code, especially if there's some d function like writeAllDigits or something similar. You can use the property .dig to get the number of significant digits of a number: writeln(PI.dig); // => 18 You still need to account for the numbers before the dot. If you're happy with scientific notation you can do: auto t = format("%.*e", PI.dig, PI); writeln("PI = ",t); (By the way, you can shortcut that with writefln!"PI = %.*e"(PI.dig, PI);) If you don't want to use scientific notation, you probably need to do some calculations to find out about the number of digits before the dot (you need abs to make it work for negative numbers too): import std.conv: to; auto x = to!int(log10(abs(PI))); writefln!"%*.*f"(x,PI.digx,PI); 
October 09 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to berni44  On Wednesday, 9 October 2019 at 05:46:12 UTC, berni44 wrote:
> On Tuesday, 8 October 2019 at 20:37:03 UTC, dan wrote:
>> But i would like to be able to do this without knowing the expansion of pi, or writing too much code, especially if there's some d function like writeAllDigits or something similar.
>
> You can use the property .dig to get the number of significant digits of a number:
>
> writeln(PI.dig); // => 18
>
> You still need to account for the numbers before the dot. If you're happy with scientific notation you can do:
>
> auto t = format("%.*e", PI.dig, PI);
> writeln("PI = ",t);
Using the '.dig' property is a really nice idea and looks very useful for this. A clarification though  It's the significant digits in the data type, not the value. (PI is 18 because it's a real, not a double.) So:
writeln(1.0f.dig, ", ", float.dig); => 6, 6
writeln(1.0.dig, ", ", double.dig); => 15, 15
writeln(1.0L.dig, ", ", real.dig); => 18, 18
Another possibility would be to combine the '.dig' property with the "%g" option, similar to the use "%e" shown. For example, these lines:
writeln(format("%0.*g", PI.dig, PI));
writeln(format("%0.*g", double.dig, 1.0));
writeln(format("%0.*g", double.dig, 100.0));
writeln(format("%0.*g", double.dig, 1.00000001));
writeln(format("%0.*g", double.dig, 0.00000001));
produce:
3.14159265358979324
1
100
1.00000001
1e08
Hopefully experimenting with the different formatting options available will yield one that works for your use case.

October 09 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to Jon Degenhardt  On Wednesday, 9 October 2019 at 07:16:43 UTC, Jon Degenhardt wrote:
> On Wednesday, 9 October 2019 at 05:46:12 UTC, berni44 wrote:
>> On Tuesday, 8 October 2019 at 20:37:03 UTC, dan wrote:
>>> But i would like to be able to do this without knowing the expansion of pi, or writing too much code, especially if there's some d function like writeAllDigits or something similar.
>>
>> You can use the property .dig to get the number of significant digits of a number:
>>
>> writeln(PI.dig); // => 18
>>
>> You still need to account for the numbers before the dot. If you're happy with scientific notation you can do:
>>
>> auto t = format("%.*e", PI.dig, PI);
>> writeln("PI = ",t);
>
> Using the '.dig' property is a really nice idea and looks very useful for this. A clarification though  It's the significant digits in the data type, not the value. (PI is 18 because it's a real, not a double.) So:
>
> writeln(1.0f.dig, ", ", float.dig); => 6, 6
> writeln(1.0.dig, ", ", double.dig); => 15, 15
> writeln(1.0L.dig, ", ", real.dig); => 18, 18
>
> Another possibility would be to combine the '.dig' property with the "%g" option, similar to the use "%e" shown. For example, these lines:
>
> writeln(format("%0.*g", PI.dig, PI));
> writeln(format("%0.*g", double.dig, 1.0));
> writeln(format("%0.*g", double.dig, 100.0));
> writeln(format("%0.*g", double.dig, 1.00000001));
> writeln(format("%0.*g", double.dig, 0.00000001));
>
> produce:
>
> 3.14159265358979324
> 1
> 100
> 1.00000001
> 1e08
>
> Hopefully experimenting with the different formatting options available will yield one that works for your use case.
Good solution
But what does it takes to leave a number the way it is without formatting automatic to 6 significant figure out how that requires such a work around as shown above. I know C language is the same but must D follow suit.
One of the compilers, i think the DMD 2.084 (not sure now) correct but now the recent one's have revert back. Every number should be left the way it is like java, C#(not sure), actionscript, javascript, etc.
I don't think it will take that much effort for trivial things like to stress developers.
This is the best solution i have ever seen on this issue on the forum.i have ask this question several times on this forum

October 09 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to dan  On Tuesday, 8 October 2019 at 20:37:03 UTC, dan wrote:
> I have a double precision number that i would like to print all significant digits of, but no more than what are actually present in the number. Or more exactly, i want to print the minimum number of digits necessary to recover the original number to within 2 or 3 least significant bits in the stored, incore, version of its bit pattern.
>
> For example,
>
>
> import std.string;
> import std.stdio;
> import std.math;
>
> void main( ) {
> auto t = format("%3.30f", PI );
> writeln("Value of PI is: ", PI, " or, : ", t);
> }
>
> The default way writeln prints is 5 digits to the right of the decimal point.
>
> I can format to print with any number of digits, such as 30 above, but that's too many.
>
> For pi, the correct number of digits to print looks to be about 18 (and the extra 12 digits presumably are from the decimal expansion of the least significant bit?).
>
> But i would like to be able to do this without knowing the expansion of pi, or writing too much code, especially if there's some d function like writeAllDigits or something similar.
>
> Thanks in advance for any pointers!
>
> dan
Hi Dan,
What's your usecase here, e.g. a csv/json reader / writer? You say it's for double precision numbers (64bit format) then provide an example for reals (80bit format). So I'm not certain your goal.
If you google "what every developer should know about doubles" you'll hit a number of useful articles that explain the common issues of floating point representation in detail.
 David

October 10 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to David Briant  On Wednesday, 9 October 2019 at 10:54:49 UTC, David Briant wrote:
> On Tuesday, 8 October 2019 at 20:37:03 UTC, dan wrote:
>> I have a double precision number that i would like to print all significant digits of, but no more than what are actually present in the number. Or more exactly, i want to print the minimum number of digits necessary to recover the original number to within 2 or 3 least significant bits in the stored, incore, version of its bit pattern.
>>
>> For example,
>>
>>
>> import std.string;
>> import std.stdio;
>> import std.math;
>>
>> void main( ) {
>> auto t = format("%3.30f", PI );
>> writeln("Value of PI is: ", PI, " or, : ", t);
>> }
>>
>> The default way writeln prints is 5 digits to the right of the decimal point.
>>
>> I can format to print with any number of digits, such as 30 above, but that's too many.
>>
>> For pi, the correct number of digits to print looks to be about 18 (and the extra 12 digits presumably are from the decimal expansion of the least significant bit?).
>>
>> But i would like to be able to do this without knowing the expansion of pi, or writing too much code, especially if there's some d function like writeAllDigits or something similar.
>>
>> Thanks in advance for any pointers!
>>
>> dan
>
> Hi Dan,
>
> What's your usecase here, e.g. a csv/json reader / writer? You say it's for double precision numbers (64bit format) then provide an example for reals (80bit format). So I'm not certain your goal.
>
> If you google "what every developer should know about doubles" you'll hit a number of useful articles that explain the common issues of floating point representation in detail.
>
>  David
Thanks David for your reply.
Thanks also berni44 for the information about the dig attribute,
Jon for the neat packaging into one line using the attribute on the type.
Unfortunately, the version of gdc that comes with the version of debian
that i am using does not have the dig attribute yet, but perhaps i can
upgrade, and eventually i think gdc will have it.
And thanks GreatSam4sure for your reply  i searched the archives first,
but very poorly :(. But it's easy to believe that i'm not the first person
in the history of the world with this issue.
Now, my use case is nothing so useful or general as a csv/json reader/writer.
I'm just doing some computations, incorrectly i think, and i want to be
able to print out the results and feed them to other software. I'm trying
to chase down a problem and rule out as many places for error as i can, and
it just seemed strange not to be able to get all the digits out in some easy way.
But the dig attribute seems to be a big step forward, and for that i am grateful.
dan

October 10 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to dan  On Thursday, 10 October 2019 at 17:12:25 UTC, dan wrote:
> Thanks also berni44 for the information about the dig attribute,
> Jon for the neat packaging into one line using the attribute on the type.
> Unfortunately, the version of gdc that comes with the version of debian
> that i am using does not have the dig attribute yet, but perhaps i can
> upgrade, and eventually i think gdc will have it.
Glad these ideas helped. The value of the 'double.dig' property is not going to change between compilers/versions/etc. It's really a property of IEEE 754 floating point for 64 bit floats. (D specified the size of double as 64). So, if you are using double, then it's pretty safe to use 15 until the compiler you're using is further along on versions. Declare an enum or const variable to give it a name so you can track it down later.
Also, don't get thrown off by the PI is a real, not a double. D supports 80 bit floats as real, so constants like PI are defined as real. But if you convert PI to a double, it'll then have 15 significant bits of precision.
Jon

October 10 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to Jon Degenhardt  On Thu, Oct 10, 2019 at 09:13:05PM +0000, Jon Degenhardt via Digitalmarsdlearn wrote: > On Thursday, 10 October 2019 at 17:12:25 UTC, dan wrote: > > Thanks also berni44 for the information about the dig attribute, Jon > > for the neat packaging into one line using the attribute on the > > type. > > Unfortunately, the version of gdc that comes with the version of > > debian that i am using does not have the dig attribute yet, but > > perhaps i can upgrade, and eventually i think gdc will have it. What's the output of dmd version? I find it extremely odd that .dig isn't supported. AFAIK, it's been there since the early days of D. Certainly, it has been there since I started using D, which was before dmd was ever available in Debian. What's the compiler output of: pragma(msg, float.dig); ? T  Many open minds should be closed for repairs.  K5 user 
October 11 Re: formatting a float or double in a string with all significant digits kept  

 
Posted in reply to H. S. Teoh  On Thursday, 10 October 2019 at 22:44:05 UTC, H. S. Teoh wrote:
> On Thu, Oct 10, 2019 at 09:13:05PM +0000, Jon Degenhardt via Digitalmarsdlearn wrote:
>> On Thursday, 10 October 2019 at 17:12:25 UTC, dan wrote:
>> > Thanks also berni44 for the information about the dig attribute, Jon
>> > for the neat packaging into one line using the attribute on the
>> > type.
>> > Unfortunately, the version of gdc that comes with the version of
>> > debian that i am using does not have the dig attribute yet, but
>> > perhaps i can upgrade, and eventually i think gdc will have it.
>
> What's the output of dmd version? I find it extremely odd that .dig isn't supported. AFAIK, it's been there since the early days of D. Certainly, it has been there since I started using D, which was before dmd was ever available in Debian.
>
> What's the compiler output of:
>
> pragma(msg, float.dig);
>
> ?
>
>
> T
Thanks HS!
I sure thought i got a compile time error when i used .dig, but i tried
it again, and it works.
I tried the pragma, and it printed out 6, and i tried PI.dig and double.dig
and they're all working now.
Just for reference, i'm using what i think is the standard gdc on debian 9,
not dmd, and the version is 2068L.
Thanks again for your help in encouraging me to try harder, and thanks again
everybody else for all the help.
dan

Copyright © 19992018 by the D Language Foundation