(nearly) ieee 754 floating point single precisition

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

(nearly) ieee 754 floating point single precisition

#1 Post by penpen » 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. :evil: .
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.
Last edited by penpen on 20 Aug 2014 08:32, edited 15 times in total.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#2 Post by aGerman » 18 Sep 2013 07:42

Very interesting. But too much code for the moment.
I get back a bundle of error messages. Was it intended or should each of your test calls work properly?

[OT]
(is this the right translation of the german slang: "fieser Fummelkram"?)

tedious fiddling / pesky fumbling even if I'm obviously not a native English :wink:
[/OT]

Regards
aGerman

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#3 Post by penpen » 18 Sep 2013 08:15

It should run error free and this is displayed under WinXP home (actually this is the only system, where i can test it):

Code: Select all

0x00000000 <-- ".e" --> "0.0"
0x00000000 <-- ".e3" --> "0.0"
0x3E4CCCCD <-- ".2e" --> "0.2"
0x3F800000 <-- "1.e" --> "1.0"
0x00000000 <-- "+.e" --> "0.0"
0x3F800000 <-- "+1.e" --> "1.0"
0x00000000 <-- "-.e" --> "0.0"
0xBF800000 <-- "-1.e" --> "-1.0"
0x7FFFFFFF <-- "NaN        " --> "NaN"
0x7FFFFFFF <-- "+NaN       " --> "NaN"
0xFFFFFFFF <-- "-NaN       " --> "-NaN"
0x7FFFFFFF <-- "+NaN(7FFFFFFF)" --> "NaN"
0xFFFFFFFF <-- "-NaN(FFFFFFFF)" --> "-NaN"
0x7F800000 <-- "inf        " --> "inf"
0x7F800000 <-- "+inf       " --> "inf"
0xFF800000 <-- "-inf       " --> "-inf"
0x00000000 <-- "0.0" --> "0.0"
0x01234567 <-- "0x01234567        " --> "2.99881655e-38"
0x01234567 <-- "+0x01234567       " --> "2.99881655e-38"
0x81234567 <-- "-0x01234567       " --> "-2.99881655e-38"
0x447A0000 <-- "1000.0            " --> "1000.0"
0x447A0001 <-- "1000.00006        " --> "1000.00006"
0x358637BD <-- "0.000001          " --> "1.0e-6"
0x00000001 <-- "1.4e-45           " --> "1.40129846e-45"
0x00000003 <-- "4.2E-45           " --> "4.20389539e-45"
0x00800001 <-- "1.1754945E-38     " --> "1.17549449e-38"
0x00400000 <-- "5.877472E-39      " --> "5.87747175e-39"
0x41460000 <-- "12.375            " --> "12.375"
0x38D1B717 <-- "0.0001            " --> "1.0e-4"
0x3A83126F <-- "0.001             " --> "0.001"
0x3C23D70A <-- "0.01              " --> "0.01"
0x3DCCCCCD <-- "0.1               " --> "0.1"
0x3F800000 <-- "1                 " --> "1.0"
0x41200000 <-- "10                " --> "10.0"
0x42C80000 <-- "100               " --> "100.0"
0x447A0000 <-- "1000              " --> "1000.0"
0x461C4000 <-- "10000             " --> "10000.0"
0x47C35000 <-- "100000            " --> "100000.0"
0x49742400 <-- "1000000           " --> "1000000.0"
0x4B189680 <-- "10000000          " --> "1.0e7"
0x42883EFA <-- "68.123            " --> "68.123"
0x00800000 <-- "1.17549434E-38    " --> "1.17549435e-38"
0x00400000 <-- "5.877472E-39      " --> "5.87747175e-39"
0xB58637BD <-- "-1.0e-6           " --> "-1.0e-6"
0x00C00000 <-- "1.763241500000E-38" --> "1.76324153e-38"
0x00002000 <-- "1.14794E-41       " --> "1.1479437e-41"
0x00000001 <-- "1.4E-45           " --> "1.40129846e-45"
0x501502F9 <-- "1.0e10            " --> "1.0e10"
0x501502F9 <-- "+1.0e+10          " --> "1.0e10"
0xAEDBE6FF <-- "- 1.0 e -10       " --> "-1.0e-10"

penpen

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#4 Post by aGerman » 18 Sep 2013 08:22

Hmm. That's what it displays under my Win7 x86

Code: Select all

0x00000000 <-- ".e" --> "0.0"
0x00000000 <-- ".e3" --> "0.0"
0x3E4CCCCD <-- ".2e" --> "0.2"
0x3F800000 <-- "1.e" --> "1.0"
0x00000000 <-- "+.e" --> "0.0"
0x3F800000 <-- "+1.e" --> "1.0"
0x00000000 <-- "-.e" --> "0.0"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Fehlender Operand
0.0
0x00000000 <-- "-1.e" --> ""
0x7FFFFFFF <-- "NaN        " --> "NaN"
0x7FFFFFFF <-- "+NaN       " --> "NaN"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Fehlender Operand
0.0
0x00000000 <-- "-NaN       " --> ""
0x7FFFFFFF <-- "+NaN(7FFFFFFF)" --> "NaN"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Numerische Konstanten sind entweder dezimale (17),
hexadezimale (0x11) oder oktale (021) Zahlen.
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Fehlender Operand
0.0
0x00000000 <-- "-NaN(FFFFFFFF)" --> ""
0x7F800000 <-- "inf        " --> "inf"
0x7F800000 <-- "+inf       " --> "inf"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Fehlender Operand
0.0
0x00000000 <-- "-inf       " --> ""
0x00000000 <-- "0.0" --> "0.0"
0x01234567 <-- "0x01234567        " --> "2.99881655e-38"
0x01234567 <-- "+0x01234567       " --> "2.99881655e-38"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Fehlender Operand
0.0
0x00000000 <-- "-0x01234567       " --> ""
0x447A0000 <-- "1000.0            " --> "1000.0"
0x447A0001 <-- "1000.00006        " --> "1000.00006"
0x358637BD <-- "0.000001          " --> "1.0e-6"
0x00000001 <-- "1.4e-45           " --> "1.40129846e-45"
0x00000003 <-- "4.2E-45           " --> "4.20389539e-45"
0x00800001 <-- "1.1754945E-38     " --> "1.17549449e-38"
0x00400000 <-- "5.877472E-39      " --> "5.87747175e-39"
0x41460000 <-- "12.375            " --> "12.375"
0x38D1B717 <-- "0.0001            " --> "1.0e-4"
0x3A83126F <-- "0.001             " --> "0.001"
0x3C23D70A <-- "0.01              " --> "0.01"
0x3DCCCCCD <-- "0.1               " --> "0.1"
0x3F800000 <-- "1                 " --> "1.0"
0x41200000 <-- "10                " --> "10.0"
0x42C80000 <-- "100               " --> "100.0"
0x447A0000 <-- "1000              " --> "1000.0"
0x461C4000 <-- "10000             " --> "10000.0"
0x47C35000 <-- "100000            " --> "100000.0"
0x49742400 <-- "1000000           " --> "1000000.0"
0x4B189680 <-- "10000000          " --> "1.0e7"
0x42883EFA <-- "68.123            " --> "68.123"
0x00800000 <-- "1.17549434E-38    " --> "1.17549435e-38"
0x00400000 <-- "5.877472E-39      " --> "5.87747175e-39"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Fehlender Operand
0.0
0x00000000 <-- "-1.0e-6           " --> ""
0x00C00000 <-- "1.763241500000E-38" --> "1.76324153e-38"
0x00002000 <-- "1.14794E-41       " --> "1.1479437e-41"
0x00000001 <-- "1.4E-45           " --> "1.40129846e-45"
0x501502F9 <-- "1.0e10            " --> "1.0e10"
0x501502F9 <-- "+1.0e+10          " --> "1.0e10"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.
Fehlender Operand
0.0
0x00000000 <-- "- 1.0 e -10       " --> ""

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#5 Post by penpen » 18 Sep 2013 08:50

Seems Win7 doesn't like the '-' handling parts, especially with the "-NaN(FFFFFFFF)" part... should not generate so much errors, as it should have returned much more earlier.

Has Windows 7 problems with one of this?

Code: Select all

set "iPart=0xFFFFFFFF"
set /A "s=0x80000000"
set /A "float=%s%|0x7FFFFFFF"
set /A "float=%s%|0x7F800000"
set /A "float=%s%^%iPart%"

penpen

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: (nearly) ieee 754 floating point single precisition

#6 Post by jeb » 18 Sep 2013 08:59

:D Nice, but much work for only converting the numbers, without any math functions.

I got the same erros at Win7 64bit, like aGerman.

I tested
call :floatTest "-1.e"

Here it fails

Code: Select all

:: perform rounding: to nearest, ties to even
....
set /A "float=-2147483648|1065353216|0"


You could read the number explanation of dbenham at stackoverflow for the background

jeb

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#7 Post by aGerman » 18 Sep 2013 09:22

Has Windows 7 problems with one of this?

Yes indeed it has
(ECHO ON)

Code: Select all

> set "iPart=0xFFFFFFFF"

> set /A "s=0x80000000"

> set /A "float=-2147483648|0x7FFFFFFF"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

> set /A "float=-2147483648|0x7F800000"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

> set /A "float=-2147483648^0xFFFFFFFF"
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: (nearly) ieee 754 floating point single precisition

#8 Post by jeb » 18 Sep 2013 09:31

But you can solve it with the hex representation

Code: Select all

C:\temp>set /a b=-2147483648
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.


Code: Select all

C:\temp>set /a var1=0x80000000
-2147483648
C:\temp>set /a var2=var1
-2147483648
C:\temp>set /a var3=%var1%
Ungültige Zahl. Zahlen sind begrenzt auf eine Genauigkeit von 32 Bits.


This is batch, nothing make sense :)

jeb

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#9 Post by penpen » 18 Sep 2013 09:57

So if you change the line

Code: Select all

   set /A "float=%s%|%e%|%f%"
to this:

Code: Select all

   set /A "float=s|e|f"
it works using Win7?
(s is predefined using set /A "s=0x80000000", maybe i should left the /A there to not convert this number)
If that is true i agree with:[quote="jeb"]This is batch, nothing make sense :) /quote]

@jeb: i can't find the number explanation of dbenham at stackoverflow:
I have tried to search for (several) combinations of "batch numbers set /a problems win7 winxp user:dbenham ...". Do you have a link?

penpen

Edit:Does this work without errors using Win7?

Code: Select all

set "iPart=0xFFFFFFFF"
set "s=0x80000000"
set /A "float=%s%|0x7FFFFFFF"
set /A "float=%s%|0x7F800000"
set /A "float=%s%^%iPart%"

:: or that
set "iPart=0xFFFFFFFF"
set /A "s=0x80000000"
set /A "float=s|0x7FFFFFFF"
set /A "float=s|0x7F800000"
set /A "float=s^iPart"

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#10 Post by aGerman » 18 Sep 2013 10:19

Both are working but not quite the same way.

Code: Select all

@prompt $g
setlocal
set "iPart=0xFFFFFFFF"
set "s=0x80000000"
set /A "float=%s%|0x7FFFFFFF"
rem %float%
set /A "float=%s%|0x7F800000"
rem %float%
set /A "float=%s%^%iPart%"
rem %float%
endlocal
rem ~~~~~~~~~~~~~~~~~~~~~
setlocal
set "iPart=0xFFFFFFFF"
set /A "s=0x80000000"
set /A "float=s|0x7FFFFFFF"
rem %float%
set /A "float=s|0x7F800000"
rem %float%
set /A "float=s^iPart"
rem %float%
endlocal
pause


Result:

Code: Select all

>setlocal

>set "iPart=0xFFFFFFFF"

>set "s=0x80000000"

>set /A "float=0x80000000|0x7FFFFFFF"

>rem -1

>set /A "float=0x80000000|0x7F800000"

>rem -8388608

>set /A "float=0x80000000^0xFFFFFFFF"

>rem 2147483647

>endlocal

>rem ~~~~~~~~~~~~~~~~~~~~~

>setlocal

>set "iPart=0xFFFFFFFF"

>set /A "s=0x80000000"

>set /A "float=s|0x7FFFFFFF"

>rem -1

>set /A "float=s|0x7F800000"

>rem -8388608

>set /A "float=s^iPart"

>rem -1

>endlocal

>pause
Drücken Sie eine beliebige Taste . . .

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#11 Post by penpen » 18 Sep 2013 10:51

Just frustrating...
The upper testcase version is running on win7 but produces "Ungültige Zahl. Zahlen sind ... ." errors on xp,
the lower version produces no errors but wrong results on both xp and win7,
and my original version produces "Ungültige Zahl. Zahlen sind ... ." errors on win7....

The best is, i try to fix the bugs, when i have access to both win7 and winxp at the same time.
This will be next friday or saturday if i have luck.
Up to that i will trie to find and read the number explanation of dbenham at stackoverflow jeb hints to.

penpen

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: (nearly) ieee 754 floating point single precisition

#12 Post by jeb » 18 Sep 2013 11:02

I'm not sure if these are the best posts, but here is one at dostips
Rules for how CMD.EXE parses numbers
And one at stackoverflow IF failure - How can 30000000000000 equal 40000000000?

jeb

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#13 Post by aGerman » 18 Sep 2013 12:00

Next attempt with again another result :?

Code: Select all

@prompt $g &setlocal
set "iPart=0xFFFFFFFF"
set "s=0x80000000"
set /A "float=s|0x7FFFFFFF"
rem %float%
set /A "float=s|0x7F800000"
rem %float%
set /A "float=s^%iPart%"
rem %float%
pause

Code: Select all

> set "iPart=0xFFFFFFFF"

> set "s=0x80000000"

> set /A "float=s|0x7FFFFFFF"

> rem 2147483647

> set /A "float=s|0x7F800000"

> rem 2147483647

> set /A "float=s^0xFFFFFFFF"

> rem -2147483648

> pause
Drücken Sie eine beliebige Taste . . .

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: (nearly) ieee 754 floating point single precisition

#14 Post by jeb » 18 Sep 2013 12:03

I fixed the code and tested it successfully with XP/32 and Win7/64.
The changes are minimal, I replaced %var% in SET /a expressions with only var

Code: Select all

@echo off
cls
call :floatTest ".e"
call :floatTest ".e3"
call :floatTest ".2e"
call :floatTest "1.e"
call :floatTest "+.e"
call :floatTest "+1.e"
call :floatTest "-.e"
call :floatTest "-1.e"

call :floatTest "NaN        "
call :floatTest "+NaN       "
call :floatTest "-NaN       "
call :floatTest "+NaN(7FFFFFFF)"
call :floatTest "-NaN(FFFFFFFF)"

call :floatTest "inf        "
call :floatTest "+inf       "
call :floatTest "-inf       "

call :floatTest "0.0"

call :floatTest "0x01234567        "
call :floatTest "+0x01234567       "
call :floatTest "-0x01234567       "

call :floatTest "1000.0            "
call :floatTest "1000.00006        "

call :floatTest "0.000001          "
call :floatTest "1.4e-45           "
call :floatTest "4.2E-45           "
call :floatTest "1.1754945E-38     "
call :floatTest "5.877472E-39      "
call :floatTest "12.375            "

call :floatTest "0.0001            "
call :floatTest "0.001             "
call :floatTest "0.01              "
call :floatTest "0.1               "
call :floatTest "1                 "
call :floatTest "10                "
call :floatTest "100               "
call :floatTest "1000              "
call :floatTest "10000             "
call :floatTest "100000            "
call :floatTest "1000000           "
call :floatTest "10000000          "

call :floatTest "68.123            "
call :floatTest "1.17549434E-38    "
call :floatTest "5.877472E-39      "

call :floatTest "-1.0e-6           "

call :floatTest "1.763241500000E-38"
call :floatTest "1.14794E-41       "

call :floatTest "1.4E-45           "


call :floatTest "1.0e10            "
call :floatTest "+1.0e+10          "
call :floatTest "- 1.0 e -10       "

goto :eof


:floatTest
::   %~1 float string
::   %~2 variable to store the resulting int coding of the float in hexadecimal representation if present,
::       else echo hex value if undefined
   setlocal enableDelayedExpansion
   set "float="

   call :str2float "%~1" float
   call :intToHex hex "%float%"

   call :float2str %float% string

   endlocal & if "%~2" == "" ( echo %hex% ^<-- "%~1" --^> "%string%" ) else ( set "%~2=%hex%" --^> "%string%" )
   goto :eof



:intToHex
::   %~1 variable to store the hex value
::   %~2 int32 string value
::   needed only to simulate the "random_pass=$(dd..." line in procedure ":do_a_file"
   setlocal enableDelayedExpansion
   set /A "num=%~2"
   set "hex="
   set "digits=0123456789ABCDEF"
   for /L %%a in (0,1,7) do (
      set /A "nibble=num&0xF", "num>>=4"
      for %%b in (!nibble!) do set "hex=!digits:~%%b,1!!hex!"
   )
   endlocal & set "%~1=0x%hex%"
   goto :eof


:intToHex
::   %~1 variable to store the hex value
::   %~2 int32 string value
::   needed only to simulate the "random_pass=$(dd..." line in procedure ":do_a_file"
   setlocal enableDelayedExpansion
   set /A "num=%~2"
   set "hex="
   set "digits=0123456789ABCDEF"
   for /L %%a in (0,1,7) do (
      set /A "nibble=num&0xF", "num>>=4"
      for %%b in (!nibble!) do set "hex=!digits:~%%b,1!!hex!"
   )
   endlocal & set "%~1=0x%hex%"
   goto :eof


:: 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 (truncation) +3.0 +2.0 -2.0 -3.0
:: 2  toward 0                                     +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
::
:str2float
::   %~1 float string
::   %~2 variable to store the resulting int coding of the float
::   actually there is no error detection,
::   so assumed: no errorneous strings
::   set "inf=0x7F800000"
::   set "nan=0x7FFFFFFF"
::   ignore 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
::
   if "%~2" == "" exit /b 1
   if "%~1" == "" set /A "%~2=0x7FFFFFFF" & exit /b 0
   
   setlocal enableDelayedExpansion

::   divide in parts: sPart * iPart.fPart * 10^^ePart
   set "string=%~1"
   set "string= %string: =%"
   set "float="

   set "ePart=%string:*e=%"
   if "%string%" == "%ePart%" set "ePart="
   set "string=!string:e%ePart%=!"
   if not defined ePart set "ePart=0"

   set "fPart=%string:*.=%"
   if "%string%" == "%fPart%" set "fPart="
   set "string=!string:.%fPart%=!"
   if "%fPart%" == "" set "fPart=0"

   if "%string:~1,1%" == "-" (
      set "iPart=%string:~2%"
      set "sPart=-1"
   )else if "%string:~1,1%" == "+" (
      set "iPart=%string:~2%"
      set "sPart=1"
   ) else (
      set "iPart=%string:~1%"
      set "sPart=1"
   )
   if not defined iPart set "iPart=0"

::   set sign flag (s)
   if %sPart% == -1 ( set /A "s=0x80000000" ) else ( set "s=0" )

::   detect NaN, inf and hex format
   if "%iPart:~0,3%" == "NaN" ( set /A "float=s|0x7FFFFFFF"
   ) else if "%iPart:~0,3%" == "inf" ( set /A "float=s|0x7F800000"
   ) else if "%iPart:~0,2%" == "0x" ( set /A "float=s ^ iPart"
   )
   if defined float (endlocal & (if "%~2" == "" ( echo(%float%) else (set "%~2=%float%")) & goto :eof)

::   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"
   if defined iPartP (
      set "iPartP=!iPartP: =0!"
      set "string= !iPart!"
      for %%a in (4096,2048,1024,512,256,128,64,32,16,8,4,2,1) do (
         if not "!string:~%%a,1!" == "" (
            set "string=!string:~%%a!"
            set /A "ePart+=%%a"
         )
      )
      set "significand=!iPartP!!fPart!"
      set "iPartP="
   ) else (
      for /F "tokens=* delims= " %%a in ("%fPart:0= %") do set "fPartP=%%~a"
      if defined fPartP (
         set "fPartP=!fPartP: =0!"
         for %%a in (!fPartP!) do set "string= !fPart:%%a=!"
         for %%a in (4096,2048,1024,512,256,128,64,32,16,8,4,2,1) do (
            if not "!string:~%%a,1!" == "" (
               set "string=!string:~%%a!"
               set /A "ePart-=%%a"
            )
         )
         set "significand=!fPartP!"
         set "fPartP="
      ) else ( set /A "float=0"
      )
   )
   if defined float (endlocal & (if "%~2" == "" ( echo(%float%) else (set "%~2=%float%")) & goto :eof)

::   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"
   set "high=%significand:~0,9%"
   set /A "ePart-=1"
   set /a "e_2=ePart"
   set "low=%significand:~9,8%"

   for %%a in (9 4 2) do (
      set /A "c=high&1"
      if !high! GEQ 200000000 (
         set /A "high>>=1", "low=!c!!low!>>1", "e_2+=1"
         set "low=00000000!low!"
         set "low=!low:~-8!"
      )
   )


::   transform to: sPart * high_{8}.high_{7-0}low{7-0} * 2^e_2
   if %ePart% LSS 0 (
      for /L %%a in (%ePart%,1,-1) do (
         set /A "ePart+=1"
         set /A "c=!high:~-1!%%5"
         set /A "cc=c+1"

         if !high! LSS 125000000 (
            set /A "high=(((!high!-c)/5)<<3)", "e_2-=3", "ePart+=1"
            set /A "low=((!cc!!low!-100000000)/5)<<3"
         ) else (
            set /A "high=(((!high!-c)/5)<<2)", "e_2-=2", "ePart+=1"
            set /A "low=((!cc!!low!-100000000)/5)<<2"
         )

         if !low! GEQ 100000000 (
            set "c=!low:~0,1!"
            set "low=!low:~1!"
            set /A "high+=c"
         )

         set "low=00000000!low!"
         set "low=!low:~-8!"
      )
   ) else if %ePart% GTR 0 (
      for /L %%a in (%ePart%,-1,1) do (
         set /A "c=!high!&7"
         set /A "cc=c+1"

         if !high! LSS 160000000 (
            set /A "high=(((!high!-c)>>2)*5)", "e_2+=2", "ePart-=1"
            set /A "low=((!cc!!low!-100000000)>>2)*5"
         ) else (
            set /A "high=(((!high!-c)>>3)*5)", "e_2+=3", "ePart-=1"
            set /A "low=((!cc!!low!-100000000)>>3)*5"
         )

         if !low! GEQ 100000000 (
            set "c=!low:~0,1!"
            set "low=!low:~1!"
            set /A "high+=c"
         )

         set "low=00000000!low!"
         set "low=!low:~-8!"
      )
   )
   set "f=0"
   for /L %%a in (0, 1 24) do (
      if !high! GEQ 100000000 (
         set /A "f=(f<<1)+1", "high=(!high!-100000000)<<1"
      ) else (
         set /A "high<<=1", "f<<=1"
      )
      set /A "low=(1!low!-100000000)<<1"
      if !low! GEQ 100000000 (
         set "low=!low:~1!"
         set /A "high+=1"
      )
      set "low=00000000!low!"
      set "low=!low:~-8!"
   )

:: set uo round bit (r) that specifies if rounding is performed, and
:: if number is greater that the round bit (rUp: true==1 false==0); this means more bits or decimal digits are available
   set /A "r=f&1"
   set /A "f>>=1"
   set "rUp=1"
   if %high% == 0 if 1%low% == 100000000 set "rUp=0"
   

:: build float
   if %e_2% LEQ -127 (
      set "test=0"
      for /L %%a in (%e_2%,1,-127) do (
         if r == 1 set "rUp=1"
         set /A "r=f&1"
         set /A "f>>=1"
      )
      set /A "e_2=-127"
   ) else (
      if %e_2% GTR 128 (
         set "e_2=128"
      )
   )

:: perform rounding: to nearest, ties to even
   if %r% == 1 (
      if %rUp% == 1 (
         set /A "f+=1"
      ) else (
         set /A "l=f&1"
         if !l! == 1 (
            set /A "f+=1"
         )
      )
   )

   if %e_2% == -127 (
      if %f% == 8388608 set /A "e_2+=1"
   ) else (
      if %f% == 16777216 (
         set /A "e_2+=1"
         set /A "f>>=1"
      )
   )

   set /A "e=(e_2+127)<<23"
   if %e% == 255 ( set "f=0" ) else ( set /A "f&=0x007FFFFF" )
   set /A "float=s|e|f"


   endlocal & (if "%~2" == "" ( echo(%float% %~2) else (set "%~2=%float%"))
   goto :eof


:float2str
::   %~1 float value (int coding)
::   %~2 variable to store the resulting string if exists,
::       else echo string value if undefined
   setlocal enableDelayedExpansion

::   transform to: sPart * high_{8}.high_{7-0}low{7-0} * 2^e
   set "float=%~1"
   set /A "s=(float>>31)&1", "e_2=((float>>23)&0x000000FF)-127", "f=float&0x007FFFFF"
   if %s% == 1 ( set "sPart=-1" ) else ( set "sPart=1" )


   if %e_2% == -127 (
      if !f! == 0 endlocal & (if "%~2" == "" ( echo 0.0) else (set "%~2=0.0")) & goto :eof

      for /L %%a in (0,1,23) do (
         if !f! LSS 8388608 (
            set /A "e_2-=1", "f<<=1"
         )
      )
      set /A "e_2+=1"
   ) else (
      if %e_2% == 128 (
         if %f% == 0 ( endlocal & (if "%~2" == "" ( echo %sPart:1=%inf) else (set "%~2=%sPart:1=%inf")) & goto :eof
         ) else ( endlocal & (if "%~2" == "" ( echo %sPart:1=%NaN) else (set "%~2=%sPart:1=%NaN")) & goto :eof
         )
      )
      set /A "f|=0x00800000"
   )

   set "high=0"
   set "low=00000000"
   for /L %%a in (0, 1, 23) do (
      set /A "b=f&1"
      set /A "f>>=1"
      set /A "c=high&1"
      set "d=!low:~0,1!"

      if !c! == 0 (
         set /A "low=(1!low!-100000000)>>1"
      ) else (
         set /A "low=(!c!!low!)>>1"
      )

      set "low=00000000!low!"
      set "low=!low:~-8!"
      set /A "high>>=1"
      if !b! == 1 set /A "high+=100000000"
   )

::   transform to: sPart * high_{8}.high_{7-0}low{7-0} * 10^ePart
   set "ePart=0"
   if %e_2% GTR 0 (
      set /A "N=(e_2>>1)+1"
      for /L %%a in (!N!,-1,1) do (
         if !e_2! GTR !ePart! (
            set /A "c=!high:~-1!%%5"
            set /A "cc=c+1"

            if !high! LSS 125000000 (
               set /A "high=(((!high!-c)/5)<<3)", "e_2-=3", "ePart+=1"
               set /A "low=((!cc!!low!-100000000)/5)<<3"
            ) else (
               set /A "high=(((!high!-c)/5)<<2)", "e_2-=2", "ePart+=1"
               set /A "low=((!cc!!low!-100000000)/5)<<2"
            )

            if !low! GEQ 100000000 (
               set "c=!low:~0,1!"
               set "low=!low:~1!"
               set /A "high+=c"
            )

            set "low=00000000!low!"
            set "low=!low:~-8!"
         )
      )

      set /A "e_2-=ePart"
      if !e_2! LSS 0 (
         set /A "c=!high:~-1!&((1<<(-e_2))-1)"
         set /A "cc=c+1"
         set /A "high=((!high!-c)>>(-e_2))"
         set /A "low=((!cc!!low!-100000000)>>(-e_2))"
         set "low=00000000!low!"
         set "low=!low:~-8!"
         set "e_2=0"
      )

      if !high! LSS 1000000000 (
         set "high=!high!!low:~0,1!"
         set "low=!low:~1!0"
         set /A "ePart-=1"
      )
   ) else if %e_2% LSS 0 (
      set /A "N=(e_2>>1)-1"
      for /L %%a in (!N!,1,-1) do (
         if !e_2! LSS !ePart! (
            set /A "c=!high!&7"
            set /A "cc=c+1"

            if !high! LSS 160000000 (
               set /A "high=(((!high!-c)>>2)*5)", "e_2+=2", "ePart-=1"
               set /A "low=((!cc!!low!-100000000)>>2)*5"
            ) else (
               set /A "high=(((!high!-c)>>3)*5)", "e_2+=3", "ePart-=1"
               set /A "low=((!cc!!low!-100000000)>>3)*5"
            )
            if !low! GEQ 100000000 (
               set "c=!low:~0,1!"
               set "low=!low:~1!"
               set /A "high+=c"
            )
            set "low=00000000!low!"
            set "low=!low:~-8!"
         )
      )

      set /A "e_2-=ePart"
      if !e_2! GTR 0 (
         set /A "high<<=e_2", "low=((1!low!-100000000)<<e_2)"

         if !low! GEQ 100000000 (
            set /A "high+=!low:~0,1!"
            set "low=!low:~1!"
         ) else (
            set "low=00000000!low!"
            set "low=!low:~-8!"
         )

         set "e_2=0"
      )
   )

:: perform rounding: to nearest, ties to even (9th digit)
   set "r=0"
   set "rUp=0"
   if %low:~0,1% GEQ 5 set "r=1"
   if %low:~0,1% GTR 5 set "rUp=1"
   if 1%low:~1% GTR 10000000 set "rUp=1"

   if %r% == 1 (
      if %rUp% == 1 (
         set /A "high+=1"
      ) else (
         set /A "l=f&1"
         if !l! == 1 (
            set /A "high+=1"
         )
      )
   )

::perform rounding to 'nice' numbers 1: last 3 digits <= '005'
   if 1%high:~-3% LEQ 1005 set "high=%high:~0,-1%0"


::perform rounding to 'nice' numbers 2: last 4 digits <= '0050'
   if 1%high:~-4% LEQ 10050 set "high=%high:~0,-2%00"

::perform rounding to 'nice' numbers 3: last 3 digits >= '995'
   if 1%high:~-3% GEQ 1995 (
      set "high=%high:~0,-1%9"
      set /A "high+=1"
   )

::perform rounding to 'nice' numbers 4: last 4 digits >= '9950'
   if 1%high:~-4% GEQ 19950 (
      set "high=%high:~0,-2%99"
      set /A "high+=1"
   )

:: overflow checking
   if %high% GEQ 1000000000 (
      set "high=%high:~0,-1%"
      set /A "ePart+=1"
   )

::perform using 'nice' numbers 1: no trailing zeroes, except if none exits prior or after the seperator
   for /L %%a in (1,1,8) do (
      if defined high (
         if !high:~-1! == 0 (
             set "high=!high:~0,-1!"
         )
      )
   )


::perform using 'nice' numbers 2: 6 digits prior to separator or 3 digits after are allowed to avoid 'e'
   set "integer=%high:~0,1%"
   set "fraction=%high:~1%"


   if -4 LSS %ePart% if %ePart% LSS 7 (
      if %ePart% LSS 0 (
         set "integer=00%integer%"
         set "fraction=!integer:~%ePart%!"
         set "integer=0"
         set "ePart=0"
      ) else if 0 LSS %ePart% (
         if defined fraction (
            set "integer=%integer%!fraction:~0,%ePart%!"
            set "fraction=!fraction:~%ePart%!"
            set "ePart=0"
         ) else (
            set "fraction=000000"
            set "integer=%integer%!fraction:~0,%ePart%!"
            set "fraction="
            set "ePart=0"
         )
      )
   )

::perform using 'nice' numbers 3: avoid lonely separator
   if not defined integer set "integer=0"
   if not defined fraction set "fraction=0"

   set "string="
   if %sPart% == -1 set "string=-"
   set "string=%string%%integer%.%fraction%"
   if not %ePart% == 0 set "string=%string%e%ePart%"

   endlocal & (if "%~2" == "" ( echo(%string% %~2) else (set "%~2=%string%"))
   goto :eof


jeb

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#15 Post by penpen » 18 Sep 2013 12:07

@jeb
Thanks for the links: very interesting and curious behavior of set /A... .
And thanks for the correction of the algorithm to make it run using win7.

Then next i will do is addition and post it as fast as i can.

penpen

Post Reply