alexei / sprintf.js

sprintf.js is a complete open source JavaScript sprintf implementation
BSD 3-Clause "New" or "Revised" License
2.11k stars 290 forks source link

Unexpected %x behavior with negative #196

Open brandonros opened 4 years ago

brandonros commented 4 years ago
const {sprintf} = require('sprintf-js') // 1.1.2
> sprintf('%x', -4868)
'ffffecfc'

I would have expected -1304, any recommendations?

tshinnic commented 3 years ago

'hexadecimal' tends to imply "unsigned values" in programming. As an example reference the first link on searching for "printf format specifiers" says "Unsigned hexadecimal integer". Others say "unsigned int" and the like.

Hexadecimal in code is most often used to represent exact binary values concisely, including binary values that would be interpreted as negative by hardware. Hexadecimal in code is not just another number base.

While there is a '%u' for decimal numbers, to switch between signed and unsigned integer, that's a rare usage. (I've only used it when I wanted a 'bad' negative integer to be really obvious visually) The only variation I've needed for hexadecimal is covered by '%X' (which I use always)

So... sprintf-js is doing exactly the "industry-standard" thing. (I hate that term :smile:) Anything else would be surprising.

If you really want signed hexadecimal, some variation on this is needed:

function asSignedHex(v) {
    let s = v < 0 ? '-' : '+'
    v = Math.abs(v)
    return sprintf("%s%0X", s, v)
}
reviewher commented 2 years ago

The README description is vague but the behavior is consistent with other implementations.

README says:

x — yields an integer as a hexadecimal number (lower-case)

Other specs explicitly say the argument is interpreted as unsigned int:

x — The unsigned argument shall be converted to unsigned hexadecimal format