1

I need the binary code representation of an integer (unsigned byte). I found this solution, where in my case $n = 8:

    function _decBinDig($x, $n)
    {
        return substr(decbin(pow(2, $n) + $x), 1);
    }

which surprisingly takes about 74 ms, while my first try - which I thought was too slow:

    function getBinary(int $x)
    {
        return str_pad(base_convert($x, 10, 2), 8, '0', STR_PAD_LEFT);
    }

only takes about 38 ms

Is there a faster solution?

11
  • $st=""; while($n>0){ $st = ($n%2) . $st; $n=intval($n/2); } echo $st; . I don't know how you're measuring the time. Can you try this and let me know here. Thanks in advance :) Commented Jul 27, 2020 at 16:58
  • $startTime = microtime(true); getBinary(89); $endTime = microtime(true); $elapsed = round(($endTime - $startTime) * 1000000, 2); echo "Execution time : $elapsed ms"; Commented Jul 27, 2020 at 17:00
  • This approach is somewhat slower than getBinary() and does not produce the desired eight characters Commented Jul 27, 2020 at 17:10
  • 1
    To me, all 3 solutions (Your 2 solutions and the one in the answer below) take between 1.4 and 1.6 ms to solve. Ran every solution 1000 times and repeated the task 5 times. I took into account the average time, minimum time and maximum time and I've got different results as to which one is the fastest. I think the problem is too trivial and that those numbers are too low to benchmark in a regular environment as the results would be highly affected by the CPU load caused by other apps running in the background during the tests. Commented Jul 27, 2020 at 17:42
  • 1
    My point being that if you're trying to optimise this, you may think about optimising your hardware instead of software. Commented Jul 27, 2020 at 17:42

2 Answers 2

3

Benchmarked the following five functions:

// For a baseline, returns unpadded binary
function decBinPlain(int $x) {
    return decbin($x);
}

// Alas fancier than necessary:
function decBinDig(int $x) {
    return substr(decbin(pow(2, 8) + $x), 1);
}

// OP's initial test
function getBinary(int $x) {
    return str_pad(base_convert($x, 10, 2), 8, '0', STR_PAD_LEFT);
}

// OP's function using decbin()
function getDecBin(int $x) {
    return str_pad(decbin($x), 8, '0', STR_PAD_LEFT);
}

// TimBrownlaw's method
function intToBin(int $x) {
   return sprintf( "%08d", decbin($x));
}

At 500,000 iterations each, run as 10 x (50,000 @ 5), here are the stats:

[average] => [
    [decBinPlain] => 0.0912
    [getDecBin] => 0.1355
    [getBinary] => 0.1444
    [intToBin] => 0.1493
    [decBinDig] => 0.1687
]
[relative] => [
    [decBinPlain] => 100
    [getDecBin] => 148.57
    [getBinary] => 158.33
    [intToBin] => 163.71
    [decBinDig] => 184.98
]
[ops_per_sec] => [
    [decBinPlain] => 548355
    [getDecBin] => 369077
    [getBinary] => 346330
    [intToBin] => 334963
    [decBinDig] => 296443
]

The positions are consistent. OP's function, changed to use decbin in place of base_convert, is the fastest function that returns the complete result, by a very thin margin. I'd opt for decbin simply because the meaning is crystal clear. For adding in the left-padding, str_pad is less complex than sprintf. Running PHP 7.4.4 on W10 & i5-8250U, total runtime 7.11 sec.

For a baseline, calling an empty dummy function averages 0.0542 sec. Then: If you need to run this enough times to worry about minute per-op performance gains, it's more economical to have the code inline to avoid the function call. Here, the overhead from the function call is greater than the difference between the slowest and the fastest options above!

For future reference. If you're bench-marking several options, I'd recommend testing them over a single script call and over several consecutive loops of each function. That'll help even out any "lag noise" from background programs, CPU throttling (power to max if on battery!!) etc. Then, call it a couple of times and see that the numbers are stable. You'll want to do much more than 1000 iterations to get reliable numbers. Try e.g. 10K upwards for more complex functions, and 100K upwards for simpler functions. Burn it enough if you want to prove it!

Sign up to request clarification or add additional context in comments.

3 Comments

Markus AO first of all thx for diving into this topic. You´re probably right with "more economical to have the code inline to avoid the function call". On the other hand: I just got infected by Uncle Bob and discovered clean coding for me. Fascinatingly, just one video was enough to change my coding style: "... shouldn't I move this line into its own function? ..."
@BlackSenator found myself briefly debating "how much merits a function", even took a quick skim of my function library to see what all I've tucked in there over time. The bottom line for me seems to be as subjective as, "If it reasonably fits on one line, if I can type it quickly without thinking, and if it's not something that'd ever be modified at a more global scope, it's not worth a function". Now str_pad(decbin()), I'd probably not if the use case were fixed. But then again if there's a chance I might want to e.g. pad at 16 bits down the road, a function would be beneficial.
On CPU economics. My dev laptop clocks 1.1032 sec for 1M blank function calls (in a loop), of which ~0.1sec is overhead from the loop and my boot-up stuff. If I run the getDecBin function above 500K times, it takes 1.38 sec. If I run it inline 500K times, it's 0.91 sec. 100K as function: 0.32sec, 100K as inline: 0.19 sec. If you don't anticipate anywhere near that sort of volume, there's no point worrying about CPU economics. It does start becoming an issue when "good style" adds 0.2+sec to response time, or when concurrent script calls are bogging down your server.
1

There is a "nicer" method you can try out.

function intToBin(int $x)
{
   return sprintf( "%08d", decbin($x));
}

or just call the sprintf inline.

1 Comment

Thanks for the suggestion, it is the nearly the same performance in about 10% of the test cases, but unfortunately in 90% it is about 50% slower than getBinary

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.