Formatting Double Precision Numbers into Strings
QUESTION: I've run into an interesting problem. I have a double precision number that I wish to convert to a string (so I can put it into a text widget, for example). I don't know ahead of time how many significant digits will be in this number. The number could be 45.6 or -22.1234567890. If it is the latter number, I am having a very hard time converting it to a string. For example, this doesn't work:
IDL> v = String(-22.1234567890d, Format='(D0)')
IDL> Print, v
-22.123457
Is this a bug in IDL? Or am I overlooking something?
![]()
ANSWER: The answer to this question was provided on the IDL newsgroup by “biophys” in a thread entitled “Converting Doubles to Strings”.
I ran into this before when I was writing a widget program. My understanding is that the so-called natural width which you are trying to use in your example is only meaningful when you are reading ASCII data. In other words, the natural width is always tied to the digital/string representation of a number. However, the problem with the String function is that it converts numerical data in its binary representation into a string. For example, when we issue the following command to IDL:
IDL> Print, String(-22.123, Format='(D0)')
-22.122999
The string representation of this number is “-22.123”, and IDL will read it and recognize it is a floating number and convert that into its binary representation, which rounds it to -22.122999, and pass it to String function. Then it converts it into the string “-22.122999”. Similarly if you try the following command:
IDL> Print, String(-22.123d0, Format='(D0)')
-22.123000
Now IDL knows this is a double precision value and converts it first into double data, and then converts it into string with the natural width of the converted double. It ends up as “-22.123000”.
But if you really provide more than six digits after decimal point, you will see the problem illustrated in your example. Natural width seems to be fixed to six digits after decimal point no matter whether the number to be converted is a float or a double.
IDL> Print, String(-22.1234567890, Format='(D0)')
-22.123457
IDL> Print, String(-22.1234567890d0, Format='(D0)')
-22.123457
If you use full width, you will get this:
IDL> Print, String(-22.1234567890, Format='(D)')
-22.1234570
IDL> Print, String(-22.1234567890d0, Format='(D)')
-22.1234567889999987
So the bottom line is that numbers in digits are always rounded and stored in binary representation on the computer. This means exact digital representation of float/double numbers only exist in some “string representation”. Once the number is taken by the machine and stored in its closest binary representation you lose all the width information of the original digital representation. And if later you want to have some digital representation, then you have to specify the width. Otherwise, you can either use the F0/D0 format code to get six digits after decimal point or use F/D format code to get the closest full width digital/string representation. I ended up using the latter for my widgets.
If you access the original IDL newsgroup article you can find an IDL program by Craig Markwardt that helps make these conversions from floats and doubles to strings much easier. And, several days later, Biophys himself came up with a program that I have modified slightly and made available as DBLTOSTR. I think this program does a great job doing the conversion, and I have decided to use this in programs like FSC_INPUTFIELD and FSC_FIELD to do the double conversions.
![]()
Generalized Number Formatter for Widgets
This business of formatting numbers for use in text widgets comes up over and over for me. If I don't know ahead of time what format my number will be in, it is a gigantic pain in the back side! I finally got tired of it and wrote my own general purpose number formatter, named--naturally--Number_Formatter.
It is possible with Number_Formatter to specify the number of decimal places you want in the output number.
IDL> Print, Number_Formatter(34.084689)
34.08469
IDL> Print, Number_Formatter(34.084689, DECIMAL=3)
34.085
And the Number_Formatter also works with exponential numbers. Note that the leading zeros in exponents are removed by the formatter.
IDL> Print, Number_Formatter(34.084689e-009, DECIMAL=3)
3.408e-8
Last Updated 10 March 2006
