(nearly) ieee 754 floating point single precisition
Posted: 17 Sep 2013 15:15
I had to program a string to float and vice versa conversion in pure batch: additional exes/cscript/... all not allowed. .
It was a pain to me to do such tedious fiddling ("fieser Fummelkram"), and i
want to save the trouble for others that have to do this, too, so i've posted it here.
Hopefully someone has fun with this.
As batch scripts don't know the float format, the string to float converts to signed integer 32, but it's hex value is that of
the float value, so just use the intToHex procedure to get this hex value.
This is not full ieee 754 floating point, as rounding precistion is only estimated, but the difference should be not that big.
The code actually is unoptimized, and i haven't actually programmed floating point division, and i don't know when i have
the time to finish these tasks. Feel free to solve these tasks, if you want.
Special thanks for finding/fixing bugs and/or supporting with code (for more information see the postings below) to:
aGerman
carlsomo
dbenham
einstein1969
jeb
I have split the whole into two parts:
- floaty.bat (the test cases)
- loadFloat.bat (that contains the macros)
This may help, if you want to read the source of the macros more easily;
it also contains the file "floaty.bat":
http://www.dostips.com/forum/viewtopic.php?p=36352#p36352
I haven't deleted the step by step comments and the test cases.
Here is what i've got so far:
- $str2float: string to float (int coding)
- $float2str: float (int coding) to string
- $floatAdd: addition
- $floatSub: substraction
- $floatMul: multiplication
- $intToHex: converts an integer string to hexadecimal notation (not really needed but is easier to compare).
The content of "loadFloat.bat" (macros):
A batch/JScript hybrid conversion can be found here:http://www.dostips.com/forum/viewtopic.php?p=33820#p33820
penpen
Edit: Corrected some flaws.
Edit2: Changed this: [It was a pain to me to do such incidentals (is this the right translation of the german slang: "fieser Fummelkram"?)] to
[It was a pain to me to do such tedious fiddling ("fieser Fummelkram"),].
Edit3: Applied jebs changes to make it work under Windows 7, and added arithemtic float addition.
Further edits:
Replaced 0x80000000 by 1<<31, as it may lead to errors on WinXP64.
Fixed a bug in float2str where the fraction is cut of in step :: 'nice' numbers 2.
Cut of wrong 'nice' number steps so for the moment they're uglier.
Fixed :floatAdd by adding a "& goto :eof" on 'early' results corrected the return value on !deltaE! GEQ 25 float1 <-> float2
Added :floatSub, :floatMul.
Edit5: Added the reference to the batch/JScript conversion (near bottom).
Edit6: Bugfixed the function floatAdd: It could happen that the sum of two 24 bit numbers added could be 25 (or 26 with rounding) bits long --> then the exponent of the result must be incremented by 1 (or 2) and the fraction should be shifted left by 1 (or 2) (thanks to einstein1969).
Edit7: Added " & goto :eof" in the functions :floatAdd, and :floatMul if result is defined early (thanks to einstein1969).
Edit8-15: Completed the implementation of rounding modes (except of detecting precisition acurately), removed some bugs, and converted the functions to macros.
It was a pain to me to do such tedious fiddling ("fieser Fummelkram"), and i
want to save the trouble for others that have to do this, too, so i've posted it here.
Hopefully someone has fun with this.
As batch scripts don't know the float format, the string to float converts to signed integer 32, but it's hex value is that of
the float value, so just use the intToHex procedure to get this hex value.
This is not full ieee 754 floating point, as rounding precistion is only estimated, but the difference should be not that big.
The code actually is unoptimized, and i haven't actually programmed floating point division, and i don't know when i have
the time to finish these tasks. Feel free to solve these tasks, if you want.
Special thanks for finding/fixing bugs and/or supporting with code (for more information see the postings below) to:
aGerman
carlsomo
dbenham
einstein1969
jeb
I have split the whole into two parts:
- floaty.bat (the test cases)
- loadFloat.bat (that contains the macros)
This may help, if you want to read the source of the macros more easily;
it also contains the file "floaty.bat":
http://www.dostips.com/forum/viewtopic.php?p=36352#p36352
I haven't deleted the step by step comments and the test cases.
Here is what i've got so far:
- $str2float: string to float (int coding)
- $float2str: float (int coding) to string
- $floatAdd: addition
- $floatSub: substraction
- $floatMul: multiplication
- $intToHex: converts an integer string to hexadecimal notation (not really needed but is easier to compare).
The content of "loadFloat.bat" (macros):
Code: Select all
@echo off
:: define info header
::
::
:: macros loaded into memory by this batch file:
:: - $str2float
:: - $float2str
:: - $floatAdd
:: - $floatSub
:: - $floatMul
:: - $intToHex
::
::
:: supported modes of operation:
:: ---------------------------------------------+---+---+---+---
:: extensions (e/d: en/disabled) | e | e | e | d
:: delayed expansion (e/d: en/disabled) | e | d | d |e/d
:: run from command line (y/n: yes/no) |y/n| y | n |y/n
:: ---------------------------------------------+---+---+---+---
:: macro behaviour (l/e: load/executable) |l+e| l |l+e| -
::
::
:: This batch uses the following environment variable names
:: of the current context, and will finally undefine them:
:: - bOR
:: - #
::
::
:: rounding is applied to all floating point macros:
::
:: Rounding to integers using the IEEE 754 rules
:: No Rounding mode +2.5 +1.5 -1.5 -2.5
:: 0 to nearest, ties to even (default) +2.0 +2.0 -2.0 -2.0
:: 1 to nearest, ties away from zero +3.0 +2.0 -2.0 -3.0
:: 2 toward 0 (truncation, no rounding) +2.0 +1.0 -1.0 -2.0
:: 3 toward +inf (rounding up, or ceiling) +3.0 +2.0 -1.0 -2.0
:: 4 toward -inf (rounding down, or floor) +2.0 +1.0 -2.0 -3.0
::
:: you select a rounding mode by setting up the environment variable
:: "roundingMode" with the number of the rounding mode.
:: If none is selected, then the default is rounding mode 0.
::
::
:: some test cases:
:: %$str2float% "10"
:: %$str2float% "4"
:: %$floatAdd% "1092616192" "1082130432"
:: %$float2str% "1096810496"
:: %$floatSub% "1092616192" "1082130432"
:: %$float2str% "1086324736"
:: %$floatMul% "1092616192" "1082130432"
:: %$float2str% "1109393408"
:: %$intToHex% "305419896"
::
::
:: end define info header
:: define check for valid system state
::
:: If the extensions are disabled, the set command throws an "syntax error",
:: when assigning an equal sign ('='):
:: This is essential for complex macros, so the extensions MUST be enabled.
::
2> nul set "extensionsEnabled=true" || (
echo(Error: The extensions are disabled, no macro will be loaded into memory.
rem simulate: exit /b 1
rem if extensions are disabled the label :EOF is not found
call
goto exit
)
::
:: end define check for valid system state
:: extensions enabled
:: define $str2float
:: %~1 float string
:: %~2 variable to store the resulting int coding of the float
:: actually there is only few error detection,
:: so assumed: no errorneous strings
:: set "inf=0x7F800000"
:: set "nan=0x7FFFFFFF"
:: NaN(...), +NaN(...), -NaN(...) format: NaN, +NaN, -NaN watched
:: "", "+", "NaN", "+NaN" -> NaN == 0x7FFFFFFF == 2147483647
:: "-", "-NaN" -> -NaN == 0xFFFFFFFF == -1
:: "inf", "+inf" -> inf == 0x7F800000 == 2139095040
:: "-inf" -> -inf == 0xFF800000 == -8388608
::
(set #=0)
if "!#!" == "0" (set bOR=^^^^) else (set bOR=^^)
if "!#!" == "0" (set #=^^^^^^^^^^^^^^^!) else (set #=!)
setlocal enableExtensions disableDelayedExpansion
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
set ^"[=%%~#^<nul ^^^%LF%%LF%^<nul ^^^"
set ^"]=^<nul^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
endlocal & (
for %%# in ("") do set $str2float=@for %%N in ^(0 1^) do @if %%~N == 1 ^(%\n%
%[%
::" parse params:"^
::" first token (mandatory) := float in string representation"^
::" second token (optional) := if present then use variable to store the result to, else use STDOUT"^
%]%
set "N=0"%\n%
set "param[1]= "%\n%
set "param[2]= "%\n%
for %%P in ^(%#%params%#%^) do @^(%\n%
^>nul set /A "N+=1"%\n%
set ^"param[%#%N%#%]= %%~P^"%\n%
^)%\n%
set "N="%\n%
%[%
::" divide in parts: sPart * iPart.fPart * 10^^ePart"^
%]%
set ^"string=%#%param[1]%#%^"%\n%
set ^"string= %#%string: =%#%^"%\n%
set "float="%\n%
%\n%
set ^"ePart=%#%string:*e=%#%^"%\n%
if not defined ePart ^(%\n%
set "ePart=e"%\n%
set ^"string=%#%string:e=%#%^"%\n%
^) else if ^"%#%string%#%^" == ^"%#%ePart%#%^" ^(%\n%
set "ePart=0"%\n%
^) else ^(%\n%
for %%a in ^(^"%#%ePart%#%^"^) do @set ^"string=%#%string:e%%~a=%#%^"%\n%
^)%\n%
%\n%
set ^"fPart=%#%string:*.=%#%^"%\n%
if not defined fPart ^(%\n%
set "fPart=f"%\n%
set ^"string=%#%string:.=%#%^"%\n%
^) else if ^"%#%string%#%^" == ^"%#%fPart%#%^" ^(%\n%
set "fPart=0"%\n%
^) else ^(%\n%
for %%a in ^(^"%#%fPart%#%^"^) do @set ^"string=%#%string:.%%~a=%#%^"%\n%
^)%\n%
%\n%
if ^"%#%string:~1,1%#%^" == "-" ^(%\n%
set ^"iPart=%#%string:~2%#%^"%\n%
set "sPart=-"%\n%
^) else if ^"%#%string:~1,1%#%^" == "+" ^(%\n%
set ^"iPart=%#%string:~2%#%^"%\n%
set "sPart="%\n%
^) else ^(%\n%
set ^"iPart=%#%string:~1%#%^"%\n%
set "sPart="%\n%
^)%\n%
if not defined iPart set "iPart=i"%\n%
%[%
::" set sign flag (s)"^
%]%
if defined sPart ^( ^>nul set /A "s=1<<31" ^) else ^( set "s=0" ^)%\n%
%[%
::" detect NaN, inf and hex format"^
%]%
if ^"%#%iPart:~0,3%#%^" == "NaN" ^(%\n%
for /F "tokens=1,2 delims=+-() " %%a in ^(^"%#%param[1]%#%^"^) do @^(%\n%
if "%%~b" == "" ^(%\n%
^>nul set /A "float=s|0x7FFFFFFF"%\n%
^) else ^(%\n%
set "float=%%~b"%\n%
^>nul set /A ^"float=^(0x%#%float:~0,1%#%^<^<28^)+0x%#%float:~1%#%^"%\n%
^>nul set /A "float=s%bOR%float"%\n%
^)%\n%
^)%\n%
^) else if ^"%#%iPart:~0,3%#%^" == "inf" ^( ^>nul set /A "float=s|0x7F800000"%\n%
^) else if ^"%#%iPart:~0,2%#%^" == "0x" ^( ^>nul set /A "float=s%bOR%iPart"%\n%
^) else if ^"%#%iPart%#%%#%fPart%#%^" == "if" ^( ^>nul set /A "float=s|0x7FFFFFFF"%\n%
^) else if ^"%#%ePart%#%^" == "e" ^( ^>nul set /A "float=s|0x7FFFFFFF"%\n%
^) else ^(%\n%
%[%
::" normalize to: sPart * 0.significand * 10^ePart, 0.significand >= 0.1"^
::" AND"^
::" detect 0.0"^
%]%
for /F "tokens=* delims= " %%a in ^(^"%#%iPart:0= %#%^"^) do @set "iPartP=%%~a"%\n%
for /F "tokens=* delims= " %%a in ^(^"%#%fPart:0= %#%^"^) do @set "fPartP=%%~a"%\n%
%\n%
if ^"%#%iPartP%#%%#%fPartP%#%^" == "" ^(%\n%
^>nul set /A "float=s"%\n%
^) else ^(%\n%
if defined iPartP ^(%\n%
set ^"iPartP=%#%iPartP: =0%#%^"%\n%
set ^"fPartP=%#%fPart%#%^"%\n%
set ^"string= %#%iPartP%#%^"%\n%
set "op=+"%\n%
^) else if defined fPartP ^(%\n%
set ^"fPartP=%#%fPartP: =0%#%^"%\n%
for %%a in ^(%#%fPartP%#%^) do @set ^"string= %#%fPart:%%a=%#%^"%\n%
set "op=-"%\n%
^)%\n%
%\n%
for %%a in ^(4096,2048,1024,512,256,128,64,32,16,8,4,2,1^) do @if not ^"%#%string:~%%a,1%#%^" == "" ^(%\n%
set ^"string=%#%string:~%%a%#%^"%\n%
^>nul set /A ^"ePart%#%op%#%=%%a^"%\n%
^)%\n%
%\n%
set ^"significand=%#%iPartP%#%%#%fPartP%#%^"%\n%
set "iPartP="%\n%
set "fPartP="%\n%
%[%
::" drop unneeded digits"^
::" transform to: sPart * high_{8}.high_{7-0}low{7-0} * 5^ePart * 2^e_2"^
%]%
set ^"significand=%#%significand:~0,17%#%0000000000000000^"%\n%
set ^"high=%#%significand:~0,9%#%^"%\n%
set ^"low=%#%significand:~9,8%#%^"%\n%
^>nul set /A "ePart-=1"%\n%
^>nul set /A "e_2=ePart"%\n%
%[%
::" iterate on: 987654321; up to three times"^
%]%
set "string= 8 4 2 "%\n%
for %%a in ^(^"%#%high:~0,1%#%^"^) do @for %%b in ^(%#%string:~-%%~a%#%^) do @^(%\n%
^>nul set /A "c=(high&1)+1"%\n%
set ^"low=%#%c%#%%#%low%#%^"%\n%
^>nul set /A "high>>=1", "low=(low>>1)-50000000", "e_2+=1"%\n%
set ^"low=00000000%#%low%#%^"%\n%
set ^"low=%#%low:~-8%#%^"%\n%
^)%\n%
set "string="%\n%
set "c="%\n%
%[%
::" transform to: sPart * high_{8}.high_{7-0}low{7-0} * 2^e_2"^
%]%
if %#%ePart%#% LSS 0 ^(%\n%
for /L %%a in ^(%#%ePart%#%,1,-1^) do @^(%\n%
^>nul set /A ^"c=%#%high:~-1%#%%%5^"%\n%
^>nul set /A "cc=c+1"%\n%
%\n%
if %#%high%#% LSS 125000000 ^(%\n%
^>nul set /A "high=(((high-c)/5)<<3)", "e_2-=3"%\n%
^>nul set /A ^"low=^(^(%#%cc%#%%#%low%#%-100000000^)/5^)^<^<3^"%\n%
^) else ^(%\n%
^>nul set /A "high=(((high-c)/5)<<2)", "e_2-=2"%\n%
^>nul set /A ^"low=^(^(%#%cc%#%%#%low%#%-100000000^)/5^)^<^<2^"%\n%
^)%\n%
%\n%
if %#%low%#% GEQ 100000000 ^(%\n%
set ^"c=%#%low:~0,1%#%^"%\n%
set ^"low=%#%low:~1%#%^"%\n%
^>nul set /A "high+=c"%\n%
^)%\n%
%\n%
set ^"low=00000000%#%low%#%^"%\n%
set ^"low=%#%low:~-8%#%^"%\n%
^)%\n%
^) else if %#%ePart%#% GTR 0 ^(%\n%
for /L %%a in ^(%#%ePart%#%,-1,1^) do @^(%\n%
^>nul set /A "c=high&7"%\n%
^>nul set /A "cc=c+1"%\n%
%\n%
if %#%high%#% LSS 160000000 ^(%\n%
^>nul set /A ^"high=^(^(^(%#%high%#%-c^)^>^>2^)*5^)^", "e_2+=2"%\n%
^>nul set /A ^"low=^(^(%#%cc%#%%#%low%#%-100000000^)^>^>2^)*5^"%\n%
^) else ^(%\n%
^>nul set /A ^"high=^(^(^(%#%high%#%-c^)^>^>3^)*5^)^", "e_2+=3"%\n%
^>nul set /A ^"low=^(^(%#%cc%#%%#%low%#%-100000000^)^>^>3^)*5^"%\n%
^)%\n%
%\n%
if %#%low%#% GEQ 100000000 ^(%\n%
set ^"c=%#%low:~0,1%#%^"%\n%
set ^"low=%#%low:~1%#%^"%\n%
^>nul set /A "high+=c"%\n%
^)%\n%
%\n%
set ^"low=00000000%#%low%#%^"%\n%
set ^"low=%#%low:~-8%#%^"%\n%
^)%\n%
^)%\n%
set "ePart="%\n%
%[%
::" compute fraction bits (f)"^
::" setup maxIndex of bits to be computed: denormalized ones with e_2 <= 127;"^
::" set e_2 to 127 although the exponent of denormalized float is 126 - coding."^
::" maxIndex := 24+(127+!e_2!)-1 == 150+!e_2!"^
%]%
if %#%e_2%#% LEQ -127 ^(%\n%
^>nul set /A "maxIndex=150+e_2"%\n%
set "e_2=-127"%\n%
^) else if %#%e_2%#% GEQ 128 ^(%\n%
set "maxIndex=-1"%\n%
^) else ^(%\n%
set "maxIndex=24"%\n%
^)%\n%
%\n%
set "f=0"%\n%
for /L %%a in ^(0, 1, %#%maxIndex%#%^) do @^(%\n%
if ^"%#%high:~8%#%^" == "" ^(%\n%
^>nul set /A "f<<=1", "high<<=1", ^"low=^(1%#%low%#%-100000000^)^<^<1^"%\n%
^) else ^(%\n%
^>nul set /A "f=(f<<1)+1", "high=(high-100000000)<<1", ^"low=^(1%#%low%#%-100000000^)^<^<1^"%\n%
^)%\n%
if NOT ^"%#%low:~8%#%^" == "" ^(%\n%
^>nul set /A "high+=1"%\n%
set ^"low=00000000%#%low:~1%#%^"%\n%
^) else ^(%\n%
set ^"low=00000000%#%low%#%^"%\n%
^)%\n%
set ^"low=%#%low:~-8%#%^"%\n%
^)%\n%
%[%
::" set up round bit (r) that specifies if rounding is performed, and"^
::" if number is greater than the round bit (rUp: true==1 false==0); this means more bits or decimal digits are available"^
%]%
^>nul set /A "roundingMode+=0", "r=f&1", "f>>=1"%\n%
%\n%
if ^"%#%roundingMode%#%^" == "4" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 4 toward -inf [rounding down, or floor] +2.0 +1.0 -2.0 -3.0"^
%]%
if NOT ^"%#%high%#%%#%low%#%^" == "000000000" set "r=1"%\n%
if defined sPart ^>nul set /A "f+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "3" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 3 toward +inf [rounding up, or ceiling] +3.0 +2.0 -1.0 -2.0"^
%]%
if NOT ^"%#%high%#%%#%low%#%^" == "000000000" set "r=1"%\n%
if NOT defined sPart ^>nul set /A "f+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "2" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 2 toward 0 [truncation, no rounding] +2.0 +1.0 -1.0 -2.0"^
%]%
rem nothing left to do%\n%
^) else if ^"%#%roundingMode%#%^" == "1" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 1 to nearest, ties away from zero +3.0 +2.0 -2.0 -3.0"^
%]%
^>nul set /A "f+=r"%\n%
^) else ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 0 to nearest, ties to even [default] +2.0 +2.0 -2.0 -2.0"^
%]%
if %#%r%#% == 1 ^(%\n%
if ^"%#%high%#%%#%low%#%^" == "000000000" ^(%\n%
^>nul set /A "f+=(f&1)"%\n%
^) else ^(%\n%
^>nul set /A "f+=1"%\n%
^)%\n%
^)%\n%
^)%\n%
%[%
::" overflow checking"^
%]%
if ^"%#%e_2%#%^" == "-127" ^(%\n%
if ^"%#%f%#%^" == "8388608" ^>nul set /A "e_2+=1"%\n%
^) else if ^"%#%f%#%^" == "16777216" ^(%\n%
^>nul set /A "e_2+=1"%\n%
^>nul set /A "f>>=1"%\n%
^)%\n%
%\n%
%[%
::" build float"^
%]%
^>nul set /A "e=(e_2+127)<<23"%\n%
if %#%e%#% == 255 ^( set "f=0" ^) else ^( ^>nul set /A "f&=0x007FFFFF" ^)%\n%
^>nul set /A "float=s|e|f"%\n%
^)%\n%
^)%\n%
for %%a in ^(^"%#%float%#%^"^) do @for %%b in ^(^"%#%param[2]:~1%#%^"^) do @^(endlocal ^& ^(if "%%~b" == "" ^( echo %%~a^) else ^(set "%%~b=%%~a"^)^)^)%\n%
^) else setlocal enableDelayedExpansion ^& set params=,
)
(set #=)
::
:: end define $str2float
:: define $float2str
:: %~1 float value (int coding)
:: %~2 variable to store the resulting string if exists,
:: else echo string value if undefined
::
:: values for (simplified) rounding using table lookup:
::
:: float | decimal value of f == 0x1 | precisition
:: (decstr) | |
:: ----------+-----------------------------------------------------------------+-------------
:: ... | ... ... ... | ...
:: ----------+-----------------------------------------------------------------+-------------
:: 1 | 0,0000001 1920928955078125 /|\ 1 2^-23=2^-13=2^-3 | 8
:: 2 | 0,0000002 384185791015625 | 2 | 8
:: 4 | 0,0000004 76837158203125 | 5 | 8 [7-8]
:: 8 | 0,0000009 5367431640625 | 10 (hex: A) | 8-9 (7-8)
:: | | |
:: 16 | 0,000001 9073486328125 | 2 | 8
:: 32 | 0,000003 814697265625 | 4 | 8
:: 64 | 0,000007 62939453125 | 8 | 8-9 (7-8)
:: | | |
:: 128 | 0,00001 52587890625 | 2 | 8
:: 256 | 0,00003 0517578125 | 3 | 8
:: 512 | 0,00006 103515625 \|/ 6 | 9
:: ----------+-----------------------------------------------------------------+-------------
:: 1024 | 0,0001 220703125 /|\ 1 | 8
:: 2048 | 0,0002 44140625 | 2 | 8
:: 4096 | 0,0004 8828125 | 5 | 8 [7-8]
:: 8192 | 0,0009 765625 | 10 (hex: A) | 8-9 (7-8)
:: | | |
:: 16384 | 0,001 953125 | 2 | 8
:: 32768 | 0,003 90625 | 4 | 8
:: 65536 | 0,007 8125 | 8 | 9 (7-8)
:: | | |
:: 131072 | 0,01 5625 | 2 | 8
:: 262144 | 0,03 125 | 3 | 8
:: 524288 | 0,06 25 \|/ 6 | 9
:: ----------+-----------------------------------------------------------------+-------------
:: 1048576 | 0,1 25 /|\ 1 | 8
:: 2097152 | 0,2 5 | 2 | 8
:: 4194304 | 0,5 | 5 | 8 [7-8]
:: ... | ... ... ... | ...
:: legend:
:: - (x-y) implemented (reduced precisition due to too big round delta value)
:: - [x-y] i've seen this in 'wild life', but i have no idea, why ...
:: maybe because this table is imprecise; if this is true i won't fix it (higher precisition, so no problem)
:: (i've also seen lower precisition on some denormalized numbers: i have no idea... if ... true... not fix it (...))
::
:: actually not needed: set "deltaR=125A248236"
::
(set #=0)
if "!#!" == "0" (set #=^^^^^^^^^^^^^^^!) else (set #=!)
setlocal enableExtensions disableDelayedExpansion
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
set ^"[=%%~#^<nul ^^^%LF%%LF%^<nul ^^^"
set ^"]=^<nul^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
endlocal & (
for %%# in ("") do set $float2str=@for %%N in ^(0 1^) do @if "%%~N" == "1" ^(%\n%
%\n%
set "N=0"%\n%
set "param[1]= "%\n%
set "param[2]= "%\n%
for %%P in ^(%#%params%#%^) do @^(%\n%
^>nul set /A "N+=1"%\n%
set ^"param[%#%N%#%]= %%~P^"%\n%
^)%\n%
set "N="%\n%
set "string="%\n%
%[%
::" transform to: (s, e_2, f)"^
%]%
set ^"float=%#%param[1]%#%^"%\n%
^>nul set /A "s=(float>>31)&1", "e_2=((float>>23)&0x000000FF)-127", "f=float&0x007FFFFF"%\n%
if ^"%#%s%#%^" == "1" ^( set "sPart=-1" ^) else set "sPart=1"%\n%
%\n%
if ^"%#%e_2%#%^" == "128" ^(%\n%
if ^"%#%f%#%^" == "0" ^(%\n%
set ^"string=%#%sPart:1=%#%inf^"%\n%
^) else if ^"%#%f%#%^" == "8388607" ^(%\n%
set ^"string=%#%sPart:1=%#%NaN^"%\n%
^) else ^(%\n%
^>nul set /A ^"f=f^|0x00800000^"%\n%
set "hexDigits=0123456789ABCDEF"%\n%
set "value="%\n%
set "string="%\n%
for /L %%a in ^(1,1,6^) do @^(%\n%
^>nul set /A "value=f&0xF", "f>>=4"%\n%
for %%b in ^(^"%#%value%#%^"^) do @set ^"string=%#%hexDigits:~%%~b,1%#%%#%string%#%^"%\n%
^)%\n%
set ^"string=%#%sPart:1=%#%NaN^(7F%#%string%#%^)^"%\n%
^)%\n%
^) else if ^"%#%e_2%#%,%#%f%#%^" == "-127,0" ^(%\n%
set ^"string=%#%sPart:~0,-1%#%0.0^"%\n%
^) else ^(%\n%
%[%
::" transform to: sPart * high_{8}(==1).high_{7-0}low{7-0} * 2^e"^
%]%
if ^"%#%e_2%#%^" == "-127" ^(%\n%
for /L %%a in ^(0,1,23^) do @if %#%f%#% LSS 8388608 ^>nul set /A "e_2-=1", "f<<=1"%\n%
set ^>nul /A "e_2+=1"%\n%
^) else set ^>nul /A "f|=0x00800000"%\n%
%\n%
set "high=0"%\n%
set "low=00000000"%\n%
for /L %%a in ^(0, 1, 23^) do @^(%\n%
^>nul set /A "b=f&1", "f>>=1", "c=(high&1)+1"%\n%
set ^"d=%#%low:~0,1%#%^"%\n%
^>nul set /A ^"low=^(%#%c%#%%#%low%#%-100000000^)^>^>1^"%\n%
set ^"low=00000000%#%low%#%^"%\n%
set ^"low=%#%low:~-8%#%^"%\n%
^>nul set /A ^"high=^(high^>^>1^)+%#%b%#%00000000^"%\n%
^)%\n%
%[%
::" transform to: sPart * 0.high_{7-0}low{7-0} * 10^ePart"^
%]%
set "ePart=0"%\n%
if %#%e_2%#% GTR 0 ^(%\n%
^>nul set /A "N=(e_2>>1)+1"%\n%
for /L %%a in ^(%#%N%#%,-1,1^) do @^(%\n%
if %#%e_2%#% GTR %#%ePart%#% ^(%\n%
^>nul set /A ^"c=^(%#%high:~-1%#%%%5^)+1^", ^"cc=%#%low:~-1%#%%%5^"%\n%
if %#%high%#% LSS 125000000 ^(%\n%
^>nul set /A "high=(high/5)<<3", "e_2-=3", "ePart+=1", ^"low=^(^(^(%#%c%#%%#%low%#%-100000000^)/5^)^<^<3^)+^(^(cc^<^<3^)/5^)^"%\n%
^) else ^(%\n%
^>nul set /A "high=(high/5)<<2", "e_2-=2", "ePart+=1", ^"low=^(^(^(%#%c%#%%#%low%#%-100000000^)/5^)^<^<2^)+^(^(cc^<^<2^)/5^)^"%\n%
^)%\n%
if %#%low%#% GEQ 100000000 ^(%\n%
^>nul set /A ^"high+=%#%low:~0,1%#%^"%\n%
set ^"low=00000000%#%low:~1%#%^"%\n%
^) else ^(%\n%
set ^"low=00000000%#%low%#%^"%\n%
^)%\n%
set ^"low=%#%low:~-8%#%^"%\n%
^)%\n%
^)%\n%
%\n%
^>nul set /A "e_2-=ePart"%\n%
if %#%e_2%#% LSS 0 ^(%\n%
^>nul set /A ^"cc=^(%#%high:~-1%#%^&^(^(1^<^<^(-e_2^)^)-1^)^)+1^"%\n%
^>nul set /A "high>>=(-e_2)", ^"low=^(^(%#%cc%#%%#%low%#%-100000000^)^>^>^(-e_2^)^)^"%\n%
set ^"low=00000000%#%low%#%^"%\n%
set ^"low=%#%low:~-8%#%^"%\n%
set "e_2=0"%\n%
^) else ^(%\n%
set ^"low=%#%high:~-1%#%%#%low%#%^"%\n%
set ^"low=%#%low:~0,8%#%^"%\n%
set ^"high=%#%high:~0,-1%#%^"%\n%
if not defined high set "high=0"%\n%
^>nul set /A "ePart+=1"%\n%
^)%\n%
^) else if %#%e_2%#% LSS 0 ^(%\n%
^>nul set /A "N=(e_2>>1)-1", "ePart-=3"%\n%
for /L %%a in ^(%#%N%#%,1,-1^) do @^(%\n%
if %#%e_2%#% LSS %#%ePart%#% ^(%\n%
if %#%high%#% LSS 160000000 ^(%\n%
^>nul set /A "c=(high&3)+1"%\n%
^>nul set /A ^"cLow=%#%c%#%%#%low%#%-100000000^", "high=((high>>2)*5)", "e_2+=2", "ePart-=1", "low=((cLow>>2)*5)+(((cLow&2)*5)>>2)"%\n%
^) else ^(%\n%
^>nul set /A "c=(high&7)+1"%\n%
^>nul set /A ^"cLow=%#%c%#%%#%low%#%-100000000^", "high=((high>>3)*5)", "e_2+=3", "ePart-=1", "low=((cLow>>3)*5)+(((cLow&3)*5)>>3)"%\n%
^)%\n%
if %#%low%#% GEQ 100000000 ^(%\n%
^>nul set /A ^"high+=%#%low:~0,1%#%^"%\n%
set ^"low=00000000%#%low:~1%#%^"%\n%
^) else set ^"low=00000000%#%low%#%^"%\n%
set ^"low=%#%low:~-8%#%^"%\n%
^)%\n%
^)%\n%
%\n%
^>nul set /A "e_2-=(ePart+=3)"%\n%
if %#%e_2%#% LSS 0 ^(%\n%
^>nul set /A ^"cc=^(%#%high:~-1%#%^&^(^(1^<^<^(-e_2^)^)-1^)^)+1^"%\n%
^>nul set /A "high>>=(-e_2)", ^"low=^(^(%#%cc%#%%#%low%#%-100000000^)^>^>^(-e_2^)^)^"%\n%
set ^"low=00000000%#%low%#%^"%\n%
set ^"low=%#%low:~-8%#%^"%\n%
set "e_2=0"%\n%
^) else ^(%\n%
set ^"low=%#%high:~-1%#%%#%low%#%^"%\n%
set ^"low=%#%low:~0,8%#%^"%\n%
set ^"high=%#%high:~0,-1%#%^"%\n%
^>nul set /A "ePart+=1"%\n%
^)%\n%
^) else (%\n%
set ^"low=%#%high:~-1%#%%#%low%#%^"%\n%
set ^"low=%#%low:~0,8%#%^"%\n%
set ^"high=%#%high:~0,-1%#%^"%\n%
^>nul set /A "ePart+=1"%\n%
^)%\n%
%[%
::" perform rounding: see table above"^
::" initial values are upper bounds only"^
%]%
set "precisition=8889889889"%\n%
^>nul set /A "rounding+=0", "eR=(((float>>23)&0x000000FF)-127)+1000"%\n%
if %#%eR%#% EQU 873 ^>nul set /A "eR=874"%\n%
for %%a in ^(^"%#%er:~-1%#%^"^) do @^(%\n%
^>nul set /A ^"precisition=%#%precisition:~%%~a,1%#%^"%\n%
if ^"%#%precisition%#%^" == "9" ^(%\n%
if NOT ^"%#%high:~0,1%#%^" == "1" ^(%\n%
set "precisition=8"%\n%
^)%\n%
^)%\n%
if "%%~a" == "3" ^>nul set /A "precisition-=1"%\n%
if "%%~a" == "6" ^>nul set /A "precisition-=1"%\n%
^)%\n%
%[%
::" REM #1234567890 "^
::" REM i0123456789 "^
::" REM xxxxxxlr--- "^
::" REM xxxxxxxlr--- "^
::" REM xxxxxxxxlr---"^
%]%
set ^"rest=%#%high%#%%#%low%#%^"%\n%
if ^"%#%precisition%#%^" == "7" ^(%\n%
set ^"high=%#%rest:~0,6%#%^"%\n%
set ^"low=%#%rest:~6,2%#%^"%\n%
set ^"rest=%#%rest:~8%#%^"%\n%
^) else if ^"%#%precisition%#%^" == "8" ^(%\n%
set ^"high=%#%rest:~0,7%#%^"%\n%
set ^"low=%#%rest:~7,2%#%^"%\n%
set ^"rest=%#%rest:~9%#%^"%\n%
^) else ^(%\n%
set ^"high=%#%rest:~0,8%#%^"%\n%
set ^"low=%#%rest:~8,2%#%^"%\n%
set ^"rest=%#%rest:~10%#%^"%\n%
^)%\n%
%\n%
if ^"%#%roundingMode%#%^" == "4" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 4 toward -inf [rounding down, or floor] +2.0 +1.0 -2.0 -3.0"^
%]%
if ^"%#%sPart%#%^" == "-1" ^(%\n%
for /F "delims=0" %%a in ^(^"%#%low:~1%#%%#%rest%#%#^"^) do @^(%\n%
if "%%~a" == "#" ^( set ^"low=%#%low:~0,1%#%^"%\n%
^) else ^>nul set /A ^"low=%#%low:~0,1%#%+1^"%\n%
^)%\n%
^) else set ^"low=%#%low:~0,1%#%^"%\n%
^) else if ^"%#%roundingMode%#%^" == "3" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 3 toward +inf [rounding up, or ceiling] +3.0 +2.0 -1.0 -2.0"^
%]%
if ^"%#%sPart%#%^" == "1" ^(%\n%
for /F "delims=0" %%a in ^(^"%#%low:~1%#%%#%rest%#%#^"^) do @^(%\n%
if "%%~a" == "#" ^( set ^"low=%#%low:~0,1%#%^"%\n%
^) else ^>nul set /A ^"low=%#%low:~0,1%#%+1^"%\n%
^)%\n%
^) else set ^"low=%#%low:~0,1%#%^"%\n%
^) else if ^"%#%roundingMode%#%^" == "2" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 2 toward 0 [truncation, no rounding] +2.0 +1.0 -1.0 -2.0"^
%]%
rem nothing left to do%\n%
^) else if ^"%#%roundingMode%#%^" == "1" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 1 to nearest, ties away from zero +3.0 +2.0 -2.0 -3.0"^
%]%
if %#%low:~1%#% GEQ 5 ^( ^>nul set /A ^"low=%#%low:~0,1%#%+1^"%\n%
^) else set ^"low=%#%low:~0,1%#%^"%\n%
^) else ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 0 to nearest, ties to even [default] +2.0 +2.0 -2.0 -2.0"^
%]%
for /F "delims=02468" %%a in ^(^"%#%low:~0,1%#%#^"^) do @for /F "delims=0" %%b in ^(^"%#%rest%#%#^"^) do @^(%\n%
if "%%~a%%~b" == "##" ^( set ^"low=%#%low%#%0^"%\n%
^) else set ^"low=%#%low%#%1^"%\n%
^)%\n%
if %#%low:~1%#% GTR 50 ^( ^>nul set /A ^"low=%#%low:~0,1%#%+1^"%\n%
^) else set ^"low=%#%low:~0,1%#%^"%\n%
^)%\n%
%[%
::" check overflow"^
%]%
if %#%low%#% GEQ 10 ^>nul set /A ^"low=%#%low:~1%#%^", "high+=1"%\n%
%[%
::" transform to: sPart * high.low * 10^ePart, digits := #|high.low|"^
%]%
set ^"low=%#%high%#%%#%low%#%^"%\n%
set ^"digits=%#%precisition%#%^"%\n%
for %%a in ^(^"%#%precisition%#%^"^) do @if NOT ^"%#%low:~%%~a%#%^" == "" ^(%\n%
^>nul set /A "ePart+=1"%\n%
^>nul set /A "digits+=1"%\n%
^)%\n%
%[%
::" transform to: nice numbers"^
::" no leading zero (except the following explicitely allow this)"^
%]%
set ^"high=%#%low:~0,1%#%^"%\n%
set ^"low=%#%low:~1%#%^"%\n%
^>nul set /A "ePart-=1"%\n%
%[%
::" use form without exponent if possible (max 7 integer / -3 fraction digits are allowed)"^
%]%
for %%a in ^(^"%#%ePart%#%^"^) do @^(%\n%
if 1 LEQ %%~a if %%~a LSS 7 ^(%\n%
set ^"high=%#%high%#%%#%low:~0,%%~a%#%^"%\n%
set ^"low=%#%low:~%%~a%#%^"%\n%
^>nul set /A "ePart-=%%~a"%\n%
^)%\n%
if -3 LEQ %%~a if %%~a LEQ -1 ^(%\n%
set "zeroes=000000000"%\n%
for %%b in ^(^"%#%ePart%#%^"^) do @if ^"%#%low:~%%~b%#%^" == ^"%#%zeroes:~%%~b%#%^" ^(%\n%
set ^"high=000000000%#%high%#%^"%\n%
set ^"low=%#%high:~%%~a%#%%#%low%#%^"%\n%
set "high="%\n%
^>nul set /A "ePart-=%%~a"%\n%
^)%\n%
^)%\n%
^)%\n%
%[%
::" no trailing zeroes"^
%]%
for /L %%a in ^(1,1,%#%digits%#%^) do @if ^"%#%low:~-1%#%^" == "0" set ^"low=%#%low:~0,-1%#%^"%\n%
%[%
::" avoid lonely separator"^
%]%
if NOT defined high set "high=0"%\n%
if NOT defined low set "low=0"%\n%
%[%
::" create float string"^
%]%
^>nul set /A "ePart+=0"%\n%
set ^"string=%#%sPart:~0,-1%#%%#%high%#%.%#%low%#%^"%\n%
if not ^"%#%ePart%#%^" == "0" set ^"string=%#%string%#% e%#%ePart%#%^"%\n%
^)%\n%
for %%a in ^(^"%#%string%#%^"^) do @for %%b in ^(^"%#%param[2]:~1%#%^"^) do @^(endlocal ^& ^(if "%%~b" == "" ^(echo^(%%~a^) else ^(set "%%~b=%%~a"^)^)^)%\n%
^) else setlocal enableDelayedExpansion ^& set params=,
)
(set #=)
::
:: end define $float2str
:: define $floatAdd
:: %~1 summand1 float in int coding
:: %~2 summand2 float in int coding
:: %~3 resulting float in int coding
(set #=0)
if "!#!" == "0" (set bOR=^^^^) else (set bOR=^^)
if "!#!" == "0" (set #=^^^^^^^^^^^^^^^!) else (set #=!)
setlocal enableExtensions disableDelayedExpansion
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
set ^"[=%%~#^<nul ^^^%LF%%LF%^<nul ^^^"
set ^"]=^<nul^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
endlocal & (
for %%# in ("") do set $floatAdd=@for %%N in ^(0 1^) do @if %%~N == 1 ^(%\n%
set "N=0"%\n%
set "param[1]= "%\n%
set "param[2]= "%\n%
set "param[3]= "%\n%
for %%P in ^(%#%params%#%^) do @^(%\n%
^>nul set /A "N+=1"%\n%
set ^"param[%#%N%#%]= %%~P^"%\n%
^)%\n%
set "N="%\n%
set "result="%\n%
^>nul set /A "float1=param[1]", "float2=param[2]"%\n%
^>nul set /A "s1=(float1>>31)&1", "e1=((float1>>23)&0x000000FF)-127", "f1=float1&0x007FFFFF"%\n%
^>nul set /A "s2=(float2>>31)&1", "e2=((float2>>23)&0x000000FF)-127", "f2=float2&0x007FFFFF"%\n%
^>nul set /A "deltaE=(e1-e2)"%\n%
if %#%deltaE%#% LSS 0 ^>nul set /A "deltaE=-deltaE"%\n%
%\n%
if ^"%#%e1%#%^" == "128" ^(%\n%
if NOT ^"%#%e2%#%^" == "128" ^(%\n%
^>nul set /A "result=float1"%\n%
^) else if ^"%#%s1%#%^" == ^"%#%s2%#%^" ^(%\n%
^>nul set /A "result=float1|float2"%\n%
^) else ^(%\n%
^>nul set /A "result=0x7FFFFFFF"%\n%
^)%\n%
^) else if %#%e2%#% == 128 ^(%\n%
^>nul set /A "result=float2"%\n%
^) else if %#%deltaE%#% GEQ 25 ^(%\n%
if %#%e1%#% LSS %#%e2%#% ^(%\n%
^>nul set /A "result=float1"%\n%
^) else ^(%\n%
^>nul set /A "result=float2"%\n%
^)%\n%
^) else ^(%\n%
if %#%e1%#% == -127 ^( ^>nul set /A "e1+=1" ^) else ^( ^>nul set /A "f1|=0x00800000" ^)%\n%
if %#%e2%#% == -127 ^( ^>nul set /A "e2+=1" ^) else ^( ^>nul set /A "f2|=0x00800000" ^)%\n%
%[%
::" watch one more bit needed to round (<= 25 bits)"^
%]%
^>nul set /A "e1-=1", "f1<<=1", "e2-=1", "f2<<=1"%\n%
^>nul set /A "r=0", "rUp=0"%\n%
^>nul set /A "rest=0x01FFFFFF%bOR%((0x01FFFFFF>>deltaE)<<deltaE)"%\n%
%\n%
if %#%e1%#% LSS %#%e2%#% ^( ^>nul set /A "e1+=deltaE", "rest&=f1", "f1>>=(deltaE)"%\n%
^) else ^>nul set /A "e2+=deltaE", "rest&=f2", "f2>>=(deltaE)"%\n%
%\n%
if ^"%#%s1%#%^" == ^"%#%s2%#%^" ^(%\n%
^>nul set /A "sR=s1", "eR=e1", "fR=f1+f2"%\n%
^) else ^(%\n%
if %#%s1%#% == 1 set ^"f1=-%#%f1%#%^"%\n%
if %#%s2%#% == 1 set ^"f2=-%#%f2%#%^"%\n%
^>nul set /A "sR=0", "eR=e1", "fR=f1+f2"%\n%
if ^"%#%fR:~0,1%#%^" == "-" ^>nul set /A "sR=1", "fR=-fR"%\n%
^)%\n%
%\n%
^>nul set /A "deltaE=eR+126"%\n%
if %#%deltaE%#% LSS 0 ^( ^>nul set /A "deltaE=0"%\n%
^) else if %#%deltaE%#% GTR 25 ^>nul set /A "deltaE=25"%\n%
for /L %%a in ^(1,1,%#%deltaE%#%^) do @if %#%fR%#% LSS 16777216 ^>nul set /A "fR<<=1", "eR-=1"%\n%
%[%
::" perform rounding (renormalize to 24 bits again)"^
%]%
^>nul set /A "roundingMode+=0", "r=fR&1", "fR>>=1", "eR+=1"%\n%
if 0x1000000 LEQ %#%fR%#% ^>nul set /A "fR>>=1", "eR+=1"%\n%
%\n%
if ^"%#%roundingMode%#%^" == "4" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 4 toward -inf [rounding down, or floor] +2.0 +1.0 -2.0 -3.0"^
%]%
if NOT ^"%#%rest%#%^" == "0" set "r=1"%\n%
if ^"%#%sR%#%^" == "1" ^>nul set /A "fR+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "3" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 3 toward +inf [rounding up, or ceiling] +3.0 +2.0 -1.0 -2.0"^
%]%
if NOT ^"%#%rest%#%^" == "0" set "r=1"%\n%
if ^"%#%sR%#%^" == "0" ^>nul set /A "fR+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "2" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 2 toward 0 [truncation, no rounding] +2.0 +1.0 -1.0 -2.0"^
%]%
rem nothing left to do%\n%
^) else if ^"%#%roundingMode%#%^" == "1" (%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 1 to nearest, ties away from zero +3.0 +2.0 -2.0 -3.0"^
%]%
^>nul set /A "fR+=r"%\n%
^) else ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 0 to nearest, ties to even [default] +2.0 +2.0 -2.0 -2.0"^
%]%
if %#%r%#% == 1 ^(%\n%
if ^"%#%rest%#%^" == "0" ^(%\n%
^>nul set /A "fR+=(fR&1)"%\n%
^) else ^(%\n%
^>nul set /A "fR+=1"%\n%
^)%\n%
^)%\n%
^)%\n%
%[%
::" overflow checking"^
%]%
if 0x1000000 LEQ %#%fR%#% ^>nul set /A "fR>>=1", "eR+=1"%\n%
%\n%
if %#%fR%#% LSS 8388608 ^( ^>nul set /A "result=((sR&1)<<31)|fR"%\n%
^) else ^>nul set /A "result=((sR&1)<<31)|((eR+127)<<23)|(fR&0x7FFFFF)"%\n%
^)%\n%
for %%a in ^(^"%#%result%#%^"^) do @for %%b in ^(^"%#%param[3]:~1%#%^"^) do @^(endlocal ^& ^(if "%%~b" == "" ^( echo %%~a^) else ^(set "%%~b=%%~a"^)^)^)%\n%
^) else setlocal enableDelayedExpansion ^& set params=,
)
(set #=)
::
:: end define $floatAdd
:: define $floatSub
:: %~1 summand1 float in int coding
:: %~2 summand2 float in int coding
:: %~3 resulting float in int coding
(set #=0)
if "!#!" == "0" (set bOR=^^^^) else (set bOR=^^)
if "!#!" == "0" (set #=^^^^^^^^^^^^^^^!) else (set #=!)
setlocal enableExtensions disableDelayedExpansion
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
set ^"[=%%~#^<nul ^^^%LF%%LF%^<nul ^^^"
set ^"]=^<nul^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
endlocal & (
for %%# in ("") do set $floatSub=@for %%N in ^(0 1^) do @if %%~N == 1 ^(%\n%
set "N=0"%\n%
set "param[1]= "%\n%
set "param[2]= "%\n%
set "param[3]= "%\n%
for %%P in ^(%#%params%#%^) do @^(%\n%
^>nul set /A "N+=1"%\n%
set ^"param[%#%N%#%]= %%~P^"%\n%
^)%\n%
set "N="%\n%
set "result="%\n%
^>nul set /A "float1=param[1]", "float2=param[2]"%\n%
^>nul set /A "s1=(float1>>31)&1", "e1=((float1>>23)&0x000000FF)-127", "f1=float1&0x007FFFFF"%\n%
^>nul set /A "s2=(float2>>31)&1", "e2=((float2>>23)&0x000000FF)-127", "f2=float2&0x007FFFFF"%\n%
^>nul set /A "s2=(1-s2)"%\n%
^>nul set /A "deltaE=(e1-e2)"%\n%
if %#%deltaE%#% LSS 0 ^>nul set /A "deltaE=-deltaE"%\n%
%\n%
if ^"%#%e1%#%^" == "128" ^(%\n%
if NOT ^"%#%e2%#%^" == "128" ^(%\n%
^>nul set /A "result=float1"%\n%
^) else if ^"%#%s1%#%^" == ^"%#%s2%#%^" ^(%\n%
^>nul set /A "result=float1|float2"%\n%
^) else ^(%\n%
^>nul set /A "result=0x7FFFFFFF"%\n%
^)%\n%
^) else if %#%e2%#% == 128 ^(%\n%
^>nul set /A "result=float2"%\n%
^) else if %#%deltaE%#% GEQ 25 ^(%\n%
if %#%e1%#% LSS %#%e2%#% ^(%\n%
^>nul set /A "result=float1"%\n%
^) else ^(%\n%
^>nul set /A "result=float2"%\n%
^)%\n%
^) else ^(%\n%
if %#%e1%#% == -127 ^( ^>nul set /A "e1+=1" ^) else ^( ^>nul set /A "f1|=0x00800000" ^)%\n%
if %#%e2%#% == -127 ^( ^>nul set /A "e2+=1" ^) else ^( ^>nul set /A "f2|=0x00800000" ^)%\n%
%[%
::" watch one more bit needed to round (<= 25 bits)"^
%]%
^>nul set /A "e1-=1", "f1<<=1", "e2-=1", "f2<<=1"%\n%
^>nul set /A "r=0", "rUp=0"%\n%
^>nul set /A "rest=0x01FFFFFF%bOR%((0x01FFFFFF>>deltaE)<<deltaE)"%\n%
%\n%
if %#%e1%#% LSS %#%e2%#% ^( ^>nul set /A "e1+=deltaE", "rest&=f1", "f1>>=(deltaE)"%\n%
^) else ^>nul set /A "e2+=deltaE", "rest&=f2", "f2>>=(deltaE)"%\n%
%\n%
if ^"%#%s1%#%^" == ^"%#%s2%#%^" ^(%\n%
^>nul set /A "sR=s1", "eR=e1", "fR=f1+f2"%\n%
^) else ^(%\n%
if %#%s1%#% == 1 set ^"f1=-%#%f1%#%^"%\n%
if %#%s2%#% == 1 set ^"f2=-%#%f2%#%^"%\n%
^>nul set /A "sR=0", "eR=e1", "fR=f1+f2"%\n%
if ^"%#%fR:~0,1%#%^" == "-" ^>nul set /A "sR=1", "fR=-fR"%\n%
^)%\n%
%\n%
^>nul set /A "deltaE=eR+126"%\n%
if %#%deltaE%#% LSS 0 ^( ^>nul set /A "deltaE=0"%\n%
^) else if %#%deltaE%#% GTR 25 ^>nul set /A "deltaE=25"%\n%
for /L %%a in ^(1,1,%#%deltaE%#%^) do @if %#%fR%#% LSS 16777216 ^>nul set /A "fR<<=1", "eR-=1"%\n%
%[%
::" perform rounding (renormalize to 24 bits again)"^
%]%
^>nul set /A "roundingMode+=0", "r=fR&1", "fR>>=1", "eR+=1"%\n%
if 0x1000000 LEQ %#%fR%#% ^>nul set /A "fR>>=1", "eR+=1"%\n%
%\n%
if ^"%#%roundingMode%#%^" == "4" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 4 toward -inf [rounding down, or floor] +2.0 +1.0 -2.0 -3.0"^
%]%
if NOT ^"%#%rest%#%^" == "0" set "r=1"%\n%
if ^"%#%sR%#%^" == "1" ^>nul set /A "fR+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "3" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 3 toward +inf [rounding up, or ceiling] +3.0 +2.0 -1.0 -2.0"^
%]%
if NOT ^"%#%rest%#%^" == "0" set "r=1"%\n%
if ^"%#%sR%#%^" == "0" ^>nul set /A "fR+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "2" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 2 toward 0 [truncation, no rounding] +2.0 +1.0 -1.0 -2.0"^
%]%
rem nothing left to do%\n%
^) else if ^"%#%roundingMode%#%^" == "1" (%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 1 to nearest, ties away from zero +3.0 +2.0 -2.0 -3.0"^
%]%
^>nul set /A "fR+=r"%\n%
^) else ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 0 to nearest, ties to even [default] +2.0 +2.0 -2.0 -2.0"^
%]%
if %#%r%#% == 1 ^(%\n%
if ^"%#%rest%#%^" == "0" ^(%\n%
^>nul set /A "fR+=(fR&1)"%\n%
^) else ^(%\n%
^>nul set /A "fR+=1"%\n%
^)%\n%
^)%\n%
^)%\n%
%[%
::" overflow checking"^
%]%
if 0x1000000 LEQ %#%fR%#% ^>nul set /A "fR>>=1", "eR+=1"%\n%
%\n%
if %#%fR%#% LSS 8388608 ^( ^>nul set /A "result=((sR&1)<<31)|fR"%\n%
^) else ^>nul set /A "result=((sR&1)<<31)|((eR+127)<<23)|(fR&0x7FFFFF)"%\n%
^)%\n%
for %%a in ^(^"%#%result%#%^"^) do @for %%b in ^(^"%#%param[3]:~1%#%^"^) do @^(endlocal ^& ^(if "%%~b" == "" ^( echo %%~a^) else ^(set "%%~b=%%~a"^)^)^)%\n%
^) else setlocal enableDelayedExpansion ^& set params=,
)
(set #=)
::
:: end define $floatSub
:: define $floatMul
:: %~1 multiplicand1 float in int coding
:: %~2 multiplicand1 float in int coding
:: %~3 resulting float in int coding
::
:: (a1 * 2^12 + a0) * (b1 * 2^12 + b0) == a1*b1*2^24 + (a1*b0 + a0*b1)*2^12 + a0*b0
:: 1...<n>...1 * 1...<n>...1 == 1...<n-1>...1 0...<n-1>...0 1
:: => |ax*by|==2*12==24
:: let be:
:: a1*b1 = AAAAAAAAAAAAAAAAAAAAAAAA,
:: a1*b0 = BBBBBBBBBBBBCCCCCCCCCCCC,
:: a0*b1 = DDDDDDDDDDDDEEEEEEEEEEEE,
:: a0*b0 = FFFFFFFFFFFFFFFFFFFFFFFF
:: f1 * f2 == AAAAAAAAAAAAAAAAAAAAAAAA000000000000000000000000 +
:: BBBBBBBBBBBBCCCCCCCCCCCC000000000000 +
:: DDDDDDDDDDDDEEEEEEEEEEEE000000000000 +
:: FFFFFFFFFFFFFFFFFFFFFFFF
(set #=0)
if "!#!" == "0" (set bOR=^^^^) else (set bOR=^^)
if "!#!" == "0" (set #=^^^^^^^^^^^^^^^!) else (set #=!)
setlocal enableExtensions disableDelayedExpansion
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
set ^"[=%%~#^<nul ^^^%LF%%LF%^<nul ^^^"
set ^"]=^<nul^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
endlocal & (
for %%# in ("") do set $floatMul=@for %%N in ^(0 1^) do @if %%~N == 1 ^(%\n%
set "N=0"%\n%
set "param[1]= "%\n%
set "param[2]= "%\n%
set "param[3]= "%\n%
for %%P in ^(%#%params%#%^) do @^(%\n%
^>nul set /A "N+=1"%\n%
set ^"param[%#%N%#%]= %%~P^"%\n%
^)%\n%
set "N="%\n%
set "result="%\n%
^>nul set /A "float1=param[1]", "float2=param[2]"%\n%
^>nul set /A "s1=(float1>>31)&1", "e1=((float1>>23)&0x000000FF)-127", "f1=float1&0x007FFFFF"%\n%
^>nul set /A "s2=(float2>>31)&1", "e2=((float2>>23)&0x000000FF)-127", "f2=float2&0x007FFFFF"%\n%
%\n%
if ^"%#%e1%#%^" == "128" ^(%\n%
if NOT ^"%#%e2%#%^" == "128" ^(%\n%
^>nul set /A "result=((s1%bOR%s2)<<31)|((e1+127)<<23)|f1"%\n%
^) else if ^"%#%f1%#%^" == ^"%#%f2%#%^" ^(%\n%
^>nul set /A "result=((s1%bOR%s2)<<31)|((e1+127)<<23)|f1"%\n%
^) else ^(%\n%
^>nul set /A "result=((s1%bOR%s2)<<31)|0x7FFFFFFF"%\n%
^)%\n%
^) else if ^"%#%e2%#%^" == "128" ^(%\n%
^>nul set /A "result=((s1%bOR%s2)<<31)|((e2+127)<<23)|f2"%\n%
^) else ^(%\n%
if ^"%#%e1%#%^" == "-127" ^( ^>nul set /A "e1+=1" ^) else ^>nul set /A "f1|=0x00800000"%\n%
if ^"%#%e2%#%^" == "-127" ^( ^>nul set /A "e2+=1" ^) else ^>nul set /A "f2|=0x00800000"%\n%
%\n%
^>nul set /A "f11=(f1&0x00FFF000)>>12", "f10=f1&0x00000FFF"%\n%
^>nul set /A "f21=(f2&0x00FFF000)>>12", "f20=f2&0x00000FFF"%\n%
^>nul set /A "AA=f11*f21", "BC=f11*f20", "DE=f10*f21", "FF=f10*f20"%\n%
^>nul set /A "B=(BC&0x00FFF000)>>12", "C=BC&0x00000FFF"%\n%
^>nul set /A "D=(DE&0x00FFF000)>>12", "E=DE&0x00000FFF"%\n%
%\n%
^>nul set /A "fR0=((C+E)<<12)+FF"%\n%
^>nul set /A "fR1=AA+B+D+(fR0>>24)"%\n%
^>nul set /A "fR0&=0x00FFFFFF"%\n%
^>nul set /A "sR=s1%bOR%s2", "eR=e1+e2"%\n%
%\n%
^>nul set /A "fR1=(fR1<<1)|(fR0>>23)"%\n%
^>nul set /A "fR0=(fR0&0x007FFFFF)<<1"%\n%
%\n%
for /L %%a in ^(1,1,48^) do @^(%\n%
if %#%fR1%#% LSS 8388608 ^(%\n%
if %#%eR%#% GTR -127 ^(%\n%
^>nul set /A "fR1=(fR1<<1)|(fR0>>23)"%\n%
^>nul set /A "fR0=(fR0&0x007FFFFF)<<1"%\n%
^>nul set /A "eR-=1"%\n%
^)%\n%
^)%\n%
^)%\n%
%[%
::" normalize fR1 to 24 bits (rest := (last 2 bits of) fR0, as (some bits) may disappear)"^
%]%
set "rest1=fR0"%\n%
for %%a in ^(1,2^) do @if %#%fR1%#% GEQ 16777216 ^(%\n%
^>nul set /A "d=(fR1&1)<<24"%\n%
^>nul set /A "eR+=1", "fR1>>=1", "fR0|=d"%\n%
^)%\n%
%[%
::" ensure minimum representable exponent (denormalized number: -127)"^
%]%
set "rest2=fR0"%\n%
for /L %%a in ^(%#%eR%#%,1,-128^) do @^(%\n%
^>nul set /A "d=(fR1&1)<<24"%\n%
^>nul set /A "eR+=1", "fR1>>=1", "fR0|=d"%\n%
^)%\n%
%[%
::" perform rounding"^
%]%
^>nul set /A "roundingMode+=0", "r=(fR0&0x00800000)>>23", "rest=fR0&0x7FFFFF"%\n%
if ^"%#%rest%#%%#%rest1%#%%#%rest2%#%^" == "000" ^( set "rest=0"%\n%
^) else set "rest=1"%\n%
%\n%
if ^"%#%roundingMode%#%^" == "4" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 4 toward -inf [rounding down, or floor] +2.0 +1.0 -2.0 -3.0"^
%]%
if ^"%#%rest%#%^" == "1" set "r=1"%\n%
if ^"%#%sR%#%^" == "1" ^>nul set /A "fR1+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "3" (%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 3 toward +inf [rounding up, or ceiling] +3.0 +2.0 -1.0 -2.0"^
%]%
if ^"%#%rest%#%^" == "1" set "r=1"%\n%
if ^"%#%sR%#%^" == "0" ^>nul set /A "fR1+=r"%\n%
^) else if ^"%#%roundingMode%#%^" == "2" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 2 toward 0 [truncation, no rounding] +2.0 +1.0 -1.0 -2.0"^
%]%
rem nothing left to do%\n%
^) else if ^"%#%roundingMode%#%^" == "1" ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 1 to nearest, ties away from zero +3.0 +2.0 -2.0 -3.0"^
%]%
^>nul set /A "fR1+=r"%\n%
^) else ^(%\n%
%[%
::" No Rounding mode +2.5 +1.5 -1.5 -2.5"^
::" 0 to nearest, ties to even [default] +2.0 +2.0 -2.0 -2.0"^
%]%
if %#%r%#% == 1 ^(%\n%
if ^"%#%rest%#%^" == "0" ^(%\n%
^>nul set /A "fR1+=(fR1&1)"%\n%
^) else ^(%\n%
^>nul set /A "fR1+=1"%\n%
^)%\n%
^)%\n%
^)%\n%
%[%
::" overflow checking"^
%]%
if %#%fR1%#% GEQ 16777216 ^>nul set /A "eR+=1", "fR1>>=1"%\n%
%[%
::" build result (denormalized/normalized numbers and check for inf)"^
%]%
if ^"%#%eR%#%^" == "-127" ^(%\n%
^>nul set /A "fR1>>=1"%\n%
^) else ^(%\n%
if %#%eR%#% GEQ 128 ^(%\n%
^>nul set /A "fR1=0"%\n%
^) else ^(%\n%
^>nul set /A "fR1&=0x007FFFFF"%\n%
^)%\n%
^)%\n%
^>nul set /A "e=eR+127"%\n%
^>nul set /A "result=(sR<<31)|((eR+127)<<23)|fR1"%\n%
^)%\n%
%\n%
for %%a in ^(^"%#%result%#%^"^) do @for %%b in ^(^"%#%param[3]:~1%#%^"^) do @^(endlocal ^& ^(if "%%~b" == "" ^( echo %%~a^) else ^(set "%%~b=%%~a"^)^)^)%\n%
^) else setlocal enableDelayedExpansion ^& set params=,
)
(set #=)
::
:: end define $floatMul
:: define $intToHex
:: %~1 int32 string value
:: %~2 variable to store the hex value
:: for optical improvement
(set #=0)
if "!#!" == "0" (set bOR=^^^^) else (set bOR=^^)
if "!#!" == "0" (set #=^^^^^^^^^^^^^^^!) else (set #=!)
setlocal enableExtensions disableDelayedExpansion
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
set ^"[=%%~#^<nul ^^^%LF%%LF%^<nul ^^^"
set ^"]=^<nul^^^%LF%%LF%^%LF%%LF%^<nul ^^^"
endlocal & (
for %%# in ("") do set $intToHex=@for %%N in ^(0 1^) do @if %%~N == 1 ^(%\n%
set "N=0"%\n%
set "param[1]= "%\n%
set "param[2]= "%\n%
for %%P in ^(%#%params%#%^) do @^(%\n%
^>nul set /A "N+=1"%\n%
set ^"param[%#%N%#%]= %%~P^"%\n%
^)%\n%
set "N="%\n%
%\n%
^>nul set /A "num=param[1]"%\n%
set "hex= "%\n%
set "digits=0123456789ABCDEF"%\n%
for /L %%a in ^(0,1,7^) do @^(%\n%
^>nul set /A "nibble=num&0xF", "num>>=4"%\n%
for %%b in ^(%#%nibble%#%^) do @set ^"hex=%#%digits:~%%b,1%#%%#%hex%#%^"%\n%
^)%\n%
%\n%
for %%a in ^(^"0x%#%hex%#%^"^) do @for %%b in ^(^"%#%param[2]:~1%#%^"^) do @^(endlocal ^& ^(if "%%~b" == "" ^( echo %%~a^) else ^(set "%%~b=%%~a"^)^)^)%\n%
^) else setlocal enableDelayedExpansion ^& set params=,
)
(set #=)
::
:: end define $intToHex
::
:: All macros loaded to memory: return success (errorLevel == 0).
exit /b 0
:exit
A batch/JScript hybrid conversion can be found here:http://www.dostips.com/forum/viewtopic.php?p=33820#p33820
penpen
Edit: Corrected some flaws.
Edit2: Changed this: [It was a pain to me to do such incidentals (is this the right translation of the german slang: "fieser Fummelkram"?)] to
[It was a pain to me to do such tedious fiddling ("fieser Fummelkram"),].
Edit3: Applied jebs changes to make it work under Windows 7, and added arithemtic float addition.
Further edits:
Replaced 0x80000000 by 1<<31, as it may lead to errors on WinXP64.
Fixed a bug in float2str where the fraction is cut of in step :: 'nice' numbers 2.
Cut of wrong 'nice' number steps so for the moment they're uglier.
Fixed :floatAdd by adding a "& goto :eof" on 'early' results corrected the return value on !deltaE! GEQ 25 float1 <-> float2
Added :floatSub, :floatMul.
Edit5: Added the reference to the batch/JScript conversion (near bottom).
Edit6: Bugfixed the function floatAdd: It could happen that the sum of two 24 bit numbers added could be 25 (or 26 with rounding) bits long --> then the exponent of the result must be incremented by 1 (or 2) and the fraction should be shifted left by 1 (or 2) (thanks to einstein1969).
Edit7: Added " & goto :eof" in the functions :floatAdd, and :floatMul if result is defined early (thanks to einstein1969).
Edit8-15: Completed the implementation of rounding modes (except of detecting precisition acurately), removed some bugs, and converted the functions to macros.