Stdlib’s Printf allows you to print ints as unsigned octals or hexadecimals, but not as unsigned binary integers.
Does anyone have a library that can pretty print ints as binary ints? I’m in the middle of writing one, but thought I’d ask just in case I missed something.
Ideally I’m looking for something that would output 0b1_0010 or simply 10010 when I run Printf.printf "%a" pp_binary_int 18.
Bonus points if there’s a way to specify minimum widths: 0b0001_0010 for Printf.printf "%a" (pp_binary_int ~min_width:8) 18.
There doesn’t seem to be much demand for this feature. If someone can come up with a compelling argument, a good choice of letter (given that B and b are already taken), and a patch, we might include it.
Hmm… My use case is that I’m abusing int as a small bit-vector and need it for debugging. I don’t think this would count as “much demand”.
When pretty-printing stuff in anger, I’ve more-or-less stopped using Printf in favor of Fmt. It’s got enough bells-and-whistles that even for printing single lines, it’s the way to go. But either way, you can just use the “provide a function that converts to string” (for Fmt, "provide a function that pretty-prints) method to provide custom pretty-printers for your special types.
I hope that was clear; if not, I can give an example. It’s not as sweet at “%b”, but then again, it’s not very painful either.
This is code that I have used in the past (from memory):
let int_size = Sys.word_size - 1
let int2bin =
let buf = Bytes.create int_size in
fun n ->
for i = 0 to int_size - 1 do
let pos = int_size - 1 - i in
Bytes.set buf pos (if n land (1 lsl i) != 0 then '1' else '0')
done;
(* skip leading zeros *)
match Bytes.index_opt buf '1' with
| None -> "0b0"
| Some i -> "0b" ^ Bytes.sub_string buf i (int_size - i)
Still, I would expect padding zeros to be thousand-separated (that leaves the corner case when the mandated width is a multiple of 4, where you’d start with an underscore, but in that case we can blame the user for mandating an inadequate width with the alternate format).
NB: I just noticed another unexpected behavior: the + and <space> flags (prefix non-negative numbers with a plus or a space, for alignment purposes) disable the alternate format altogether.
Looks like + and <space> flags are not allowed to be used together and only there for legacy-behaviour. Try passing the -strict-formats flag to the ocaml toplevel or the compiler.