Here is another variation optimized for performance. It uses a FOR /L loop to limit the number of slow GOTO executions. The loop limit of 50 is somewhat arbitrary - it can be changed quite a bit without substantive change to performance.
I suppose a marginally faster implementation could be build by using the fast string length method to define a single loop of exactly the right length, without any need for GOTO. But I don't think it will make a significant difference.
This routine is slightly different in that the binary string is the first argument, and the variable name to be used for the return value is a second optional argument. The routine simply prints the result if no 2nd argument is given.
Also, the routine validates the binary string, printing an error if it is not valid.
Finally, it strips leading 0 digits from the result.
@echo off
:Bin2Hex binStr [rtnVar]
setlocal enableDelayedExpansion
if "%~1" equ "" (set "bin=error") else set "bin=00000%~1"
for /f "delims=01" %%A in ("%bin%") do (
echo Invalid binary value>&2
exit /b 1
)
for %%A in (
"0000=0" "0001=1" "0010=2" "0011=3" "0100=4" "0101=5" "0110=6" "0111=7"
"1000=8" "1001=9" "1010=A" "1011=B" "1100=C" "1101=D" "1110=E" "1111=F"
) do set %%A
set "hex="
:loop
for /l %%N in (1 1 50) do (
for %%N in (!bin:~-4!) do set "hex=!%%N!!hex!"
set "bin=!bin:~0,-4!"
if !bin! equ 0 for %%H in (!hex!) do (
endlocal
if "%~2" equ "" (echo %%H) else set "%~2=%%H"
exit /b 0
)
)
goto :loop
Here is a table comparing the performance characteristics of my, Aacini's, and rojo's code. The times represent the number of seconds it takes to perform one conversion:
binary | | |
string | | |
length | rojo | Aacini | dbenham
--------+-------------+----------+-----------
| | |
8 | 0.03 | 0.01 | 0.01
| | |
638 | 1.20 | 0.26 | 0.04
| | |
4000 | ERROR: CALL | 2.06 | 0.30
| stack limit | |
| exceeded | |
--------------------------------------------
As requested by rojo, here is a version that uses left shift and processes one bit at a time. It is roughly half as fast as my optimized lookup version:
@echo off
:Bin2Hex binStr [rtnVar]
setlocal enableDelayedExpansion
if "%~1" equ "" (set "bin=error") else set "bin=0000%~1"
for /f "delims=01" %%A in ("%bin%") do (
echo Invalid binary value>&2
exit /b 1
)
set "hexDigit=0123456789ABCDEF"
set "hex="
:loop
for /l %%N in (1 1 50) do (
set /a nibble=0
for /l %%n in (0 1 3) do (
set /a "nibble+=!bin:~-1!<<%%n"
set "bin=!bin:~0,-1!"
)
for %%n in (!nibble!) do set "hex=!hexDigit:~%%n,1!!hex!"
if !bin! equ 0 for %%H in (!hex!) do (
endlocal
if "%~2" equ "" (echo %%H) else set "%~2=%%H"
exit /b 0
)
)
goto :loop