Right way to show numbers in binary/hex/octal in your opinion?

Siarhei Siamashka siarhei.siamashka at gmail.com
Tue Dec 28 23:45:17 UTC 2021

On Monday, 27 December 2021 at 12:48:52 UTC, Rumbu wrote:
> How can you convert 0x8000_0000_0000_0000 to long?
> And if your response is "use a ulong", I have another one: how 
> do you convert -0x8000_0000_0000_0000 to ulong.

If you actually care about overflows safety, then both of these 
conversion attempts are invalid and should raise an exception or 
allow to handle this error in some different fashion. For 
example, Crystal language ensures overflows safety and even 
provides two varieties of string-to-integer conversion methods 
(the one with '?' in name returns nil on error, the other raises 
an exception):

puts "0000000000000000".to_i64?(16)  || "failed"  # prints 0

puts "8000000000000000".to_i64?(16)  || "failed"  # prints 
puts "-8000000000000000".to_u64?(16) || "failed"  # prints 
puts "8000000000000000".to_u64?(16)  || "failed"  # prints 
puts "-8000000000000000".to_i64?(16) || "failed"  # prints 

# Unhandled exception: Invalid Int64: 8000000000000000 
puts "8000000000000000".to_i64(16)

And Dlang is doing a similar job, though it doesn't seem to be 
able to handle negative base 16 numbers:

import std;

void main() {
   // prints 9223372036854775808
   // Exception: Unexpected '-' when converting from type string 
to type long

If you want to get rid of overflow errors, then please consider 
using a larger 128-bit type or a bigint. Or figure out what's the 
source of this out-of-range input and fix the problem there.

But if you don't care about overflows safety, then it's surely 
possible to implement another library and define conversion 
operations to wraparound any arbitrarily large input until it 
fits into the valid range for the target data type. Using this 
definition, "0x8000_0000_0000_0000" converted to long will become 
-9223372036854775808 and "-0x8000_0000_0000_0000" converted to 
ulong will become 9223372036854775808. I think that this is 
incorrect, but this mimics the two's complement wraparound 
semantics and some people may like it.

>>> This is also an issue în phobos:
>>> https://issues.dlang.org/show_bug.cgi?id=20452
>>> https://issues.dlang.org/show_bug.cgi?id=18290
>> To me this looks very much like just a self inflicted damage 
>> and historical baggage, entirely caused by making wrong 
>> choices in the past.
> No, it's just the fact that phobos doesn't use the same 
> convention for both senses of conversion. When converting from 
> number to string, it uses the internal representation - 2's 
> complement. When it is converting from string to number, it 
> uses the "human readable" convention.

The "internal representation" is ambiguous. You can't even figure 
out if FFFF is a positive or a negative number:

import std;

void main() {
   short a = -1;
   writeln(a.to!string(16)); // prints "FFFF"
   long b = 65535;
   writeln(b.to!string(16)); // prints "FFFF"
Both -1 and 65535 become exactly the same string after 
conversion. How are you going to convert it back?

Also you haven't provided any answer to my questions from the 
earlier message, so I'm repeating them again:

  1. How does this "internal representation" logic make sense for 
the bases, which are not powers of 2?

  2. If dumping numbers to strings in base 16 is intended to show 
their internal representation, then why are non-negative numbers 
not padded with zeroes on the left side (like the negative 
numbers are padded with Fs) when converted using Dlang's 

More information about the Digitalmars-d mailing list