Convert decimal number to hexadecimal number as atom with zero padding on left

Currently I can convert a decimal number to a hexadecimal number, pad it on the left with zeros and upper case the hexadecimal digits A - F using

?- Value = 13,format(atom(Atom_lower),'~|~`0t~16r~2|',[Value]),upcase_atom(Atom_lower,Atom).
Value = 13,
Atom_lower = '0d',
Atom = '0D'.

However the width is a constant, i.e. 2 and I don’t know if format/3 can take the width as an argument, something like

?- Value = 13,Width=2,format(atom(Atom_lower),'~|~`0t~16r???|',[Value,Width]),upcase_atom(Atom_lower,Atom).
Value = 13,
Atom_lower = '0d',
Atom = '0D'.

Is there something that ??? can be set to make this work? Is there a better way to do the conversion using other predicate(s)?


Right now I have

dec_to_hex(Value,Atom) :-
    Value =< 0xFF, !,
    format(atom(Atom_lower),'~|~`0t~16r~2|',Value),
    upcase_atom(Atom_lower,Atom).
dec_to_hex(Value,Atom) :-
    Value =< 0xFFFF, !,
    format(atom(Atom_lower),'~|~`0t~16r~4|',Value),
    upcase_atom(Atom_lower,Atom).
dec_to_hex(Value,Atom) :-
    Value =< 0xFFFFFFFF, !,
    format(atom(Atom_lower),'~|~`0t~16r~8|',Value),
    upcase_atom(Atom_lower,Atom).
dec_to_hex(Value,Atom) :-
    Value =< 0xFFFFFFFFFFFFFFFF,
    format(atom(Atom_lower),'~|~`0t~16r~16|',Value),
    upcase_atom(Atom_lower,Atom).
dec_to_hex(Value,Atom) :-
    format(atom(Atom_lower),'~16r',Value),
    upcase_atom(Atom_lower,Atom).

Examples

?- rfc5234:dec_to_hex(0,Atom).
Atom = '00'.

?- rfc5234:dec_to_hex(0xFF,Atom).
Atom = 'FF'.

?- rfc5234:dec_to_hex(0x100,Atom).
Atom = '0100'.

?- rfc5234:dec_to_hex(0xFFFF,Atom).
Atom = 'FFFF'.

?- rfc5234:dec_to_hex(0x10000,Atom).
Atom = '00010000'.

?- rfc5234:dec_to_hex(0xFFFFFFFFFFFFFFFFFF,Atom).
Atom = 'FFFFFFFFFFFFFFFFFF'.

Based on this old answer by Holger Kanwischer

A format/3 numerical argument can be written as *, taking the value from the next positional argument in the argument list.

1 Like

New version of code based on insight given by Jan W.

dec_to_hex(Value,Atom) :-
    hex_canonical_width(Value,Width),
    format(atom(Atom),'~|~`0t~16R~*|',[Value,Width]), !.
dec_to_hex(Value,Atom) :-
    format(atom(Atom_lower),'~16R',Value).

hex_canonical_width(Value,2) :- Value =< 0xFF, !.
hex_canonical_width(Value,4) :- Value =< 0xFFFF, !.
hex_canonical_width(Value,8) :- Value =< 0xFFFFFFFF, !.
hex_canonical_width(Value,16) :- Value =< 0xFFFFFFFFFFFFFFFF.
1 Like

The msb/1 function should allow for a bit more generalization, e.g.

110 ?- A is msb(0xFFFFFFFFFFFFFFFF+1)/4.
A = 16.

And … instead of upcase, use the ‘R’ :

113 ?- format('~16R', 378658348).
1691DE2C
2 Likes