2

I am on OSX Mavericks, trying to learn the printf command in shell and in awk. I was playing around with the different format specifiers and field precision values.

I got a very unexpected result, and I really don't understand why.

This is my code:

#!/bin/bash
a="12345.123456789012345678901"
printf "(%40.30s)\n" $a
printf "(%40.30f)\n" $a
printf "(%40.30e)\n" $a

I had expected to see something like this:

(             12345.123456789012345678901)
(    12345.123456789012345678901000000000)
(    1.234512345678901234567890100000e+04)

But instead, this is my actual result:

(             12345.123456789012345678901)
(    12345.123456789011470391415059566498)
(    1.234512345678901147039141505957e+04)

The first line worked as expected, but the numbers displayed in the 2nd and 3rd (with %f and %e respectively) were not. Notice that the first 11 decimal places were correctly displayed, but the rest were not.

I double-checked using the printf in awk and got the same modified number. (I don't know this for a fact, but based on my testing, the awk printf and the shell printf behave differently, and that is why I tested it in awk too.)

I don't think it has anything to do with rounding. Have I inadvertently triggered some octal or hexadecimal system?

Thanks.

2 Answers 2

3

17 significant digits are beyond the limit imposed by 64 bit floats (with 53 bits significant precision, and 11 bits for exponent, as defined by IEEE 754 double-precision binary floating-point format). Said differently, your number has too many digits to be accurately represented as 64 bit floating point number. It doesn't matter how many digits are left or right the decimal point: The sum of digits count matters - position of decimal point is internally represented by the exponent. Therefore you have 11+5 digits - that's 16 correct digits. What is beyond, is loss of precision.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! That actually makes sense! I am just wondering: what determines how those digits (beyond the first 16) will be changed? They are not simply trimmed or rounded, but instead they got consistently changed to something else. So clearly there is some kind of rule for handling that. Any insights?
actually, they are. Only, that truncation occurs in another number base than decimal, that's why it seems that there's no discernible pattern to it. The floating point format describes representation of those number as bits, in binary form, and not as decimal numbers.
1

On my test, output of Zsh and Awk are the same, but Bash's output is different. First thing I tried to do was check which library those tools use. Awk and Zsh uses libm.so, but Bash doesn't. I think the difference lies much with the implementation of floating-point.

    $ ldd /bin/bash
    linux-vdso.so.1 (0x00007fffb475e000)
    libreadline.so.6 => /lib64/libreadline.so.6 (0x00007fc8666d3000)
    libncurses.so.5 => /lib64/libncurses.so.5 (0x00007fc866474000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fc866270000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fc865ec5000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fc86691d000)

See also Double-precision floating-point format.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.