Skip to content

printf: %a output is different from coreutils #7364

@drinkcat

Description

@drinkcat

%a should output "Hexadecimal floating point, lowercase"

After fixing #7362, we still see some issues.

It seems like GNU coreutils prefers "shifting" the output so that we have a single hex digit between 0x1 and 0xf before the decimal point, while uutils always picks 0x1. And the output is padded with 0.

$ cargo run printf "%a %a\n" 15.125 16.125
0x1.e400000000000p+3 0x1.0200000000000p+4
$ printf "%a %a\n" 15.125 16.125
0xf.2p+0 0x8.1p+1

The value is technically correct though:

0x1.e400000000000p+3 (1+14/16+4/256)*2**3=15.125
0x1.0200000000000p+4 (1+2/256)*2**4=16.125

(note: be careful to add env before printf as some shell implementations provide built-in printf...)

Also, the behaviour is different across platforms. Running LANG=C env printf '%a %.6a\n' 0.12544 0.12544 in various dockers (gist):

arch %a %.6a
linux-386/linux-amd64 0x8.07357e670e2c12bp-6 0x8.07357ep-6
linux-arm-v5/linux-arm-v7 0x1.00e6afcce1c58p-3 0x1.00e6b0p-3
linux-arm64-v8/linux-mips64le/linux-ppc64le/linux-s390x 0x1.00e6afcce1c58255b035bd512ec7p-3 0x1.00e6b0p-3

According to https://en.cppreference.com/w/c/io/fprintf: The default precision is sufficient for exact representation of the value..

On x86, 16 nibbles = 64 bits are printed at most, including the integer part. That corresponds to the internal x86 80-bit floating point, long double type. printf shifts 3 of the fraction bits in the integer part before the ., so that the whole 64 bits can fit neatly in 16 nibbles when printed. It's interesting that this behaviour is preserved when specifying a precision (e.g. %.6f).

On arm64 (and a bunch of other archs): 28 nibbles = 112 bits are printed after the decimal point. That corresponds to quad-precision 128-bit float. Also long double type.

On arm32: 13 nibbles = 52 bits are printed. That's double-precision 64-bit float. Also long double type.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions