# 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