## (nearly) ieee 754 floating point single precisition

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

Thanks penpen!

I have tested the Sin(x) of previus post for see the error.

The result on single test is VERY GOOD!

Code: Select all

``@echo  offrem sin(x)call :sin "1.73"goto :eof:sin %1=x radiantsset x=%~1rem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880 - x^2 * 1/39916800 )))))rem calculate x^2call :floatTestMul2 "%x%" "%x%"  "xx"call :floatTestMul2 "%xx%" "2.5052108385441718775052108385442e-8" "sinp"call :floatTestSub2 "2.7557319223985890652557319223986e-6" "%sinp%" "sinp2"call :floatTestMul2 "%xx%" "%sinp2%" "sinp3"call :floatTestSub2 "1.984126984126984126984126984127e-4" "%sinp3%" "sinp4"call :floatTestMul2 "%xx%" "%sinp4%" "sinp5"call :floatTestSub2 "0.00833333333333333" "%sinp5%" "sinp6"call :floatTestMul2 "%xx%" "%sinp6%" "sinp7"call :floatTestSub2 "0.16666666666666666" "%sinp7%" "sinp8"call :floatTestMul2 "%xx%" "%sinp8%" "sinp9"call :floatTestSub2 "1" "%sinp9%" "sinp10"call :floatTestMul2 "%x%" "%sinp10%" "sin"echo Sin(%x%)=%sin%pausegoto :eof:: functions add for return a value in variable:floatTestMul2::   %~1 float string multiplicand1::   %~2 float string multiplicand2   setlocal   set "value1=%~1"   set "value2=%~2"     call :str2float "%value1%" "float1"   call :str2float "%value2%" "float2"   call :floatMul "%float1%" "%float2%" "float3"   call :intToHex "hex1" "%float1%"   call :intToHex "hex2" "%float2%"   call :intToHex "hex3" "%float3%"   call :float2str "%float3%" "string1"   rem echo %value1% * %value2% = %float1% * %float2% == %hex1% * %hex2% == %hex3% == %float3% == %string1%   endlocal & set "%~3=%string1%"   goto :eof:floatTestSub2::   %~1 float string minuend::   %~2 float string subtrahend::       else echo hex value if undefined   setlocal   set "value1=%~1"   set "value2=%~2"   call :str2float "%value1%" "float1"   call :str2float "%value2%" "float2"   call :floatSub "%float1%" "%float2%" "float3"   call :intToHex "hex1" "%float1%"   call :intToHex "hex2" "%float2%"   call :intToHex "hex3" "%float3%"   call :float2str "%float3%" "string1"   rem echo %value1% - %value2% = %float1% - %float2% == %hex1% - %hex2% == %hex3% == %float3% == %string1%   endlocal & set "%~3=%string1%"   goto :eof``

result:

Code: Select all

``Sin(1.73)=0.9873535``

the windows calculator return:
0,98735383970071645108567767622206
0.9873535

I'm very happy

You have done a very good work!

EDIT: We have the SIN(x)!!!!

einstein1969

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

Hi penpen,

There is another correction to do:

If the second operand %2 of FLOATSUB is 0 the inv is calculated:

Code: Select all

``   set /A "inv=(1<<31)^%~2"``

result:

Code: Select all

``inv = -2147483648``

and when this is assigned at variables get the error like "The numbers are limitated at 32bit precision etc..."

einstein1969

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

### Re: (nearly) ieee 754 floating point single precisition

einstein1969 wrote:We have the SIN(x)!!!!
Nice !

einstein1969 wrote:(...)
when this is assigned at variables get the error like "The numbers are limitated at 32bit precision etc..."
This is one of the reasons, why i have to revise the code:
This not only could happen in the function :floatSub, ...
it could also happen in many other locations; for example near the starts of :floatAdd :floatMul :intToHex, :float2str - but also within these functions there are some locations where this may happen.

So this time you have to wait for the bugfix; sorry for that.
You should avoid using the float representation of "-0", a hotfix for the floatSub function could be this:

Code: Select all

``:floatSub::   %~1 minuend float in int coding::   %~2 subtrahend float in int coding::   %~3 resulting float in int coding   setlocal   set /A "value=%~2"   if "%value%" == "0" (      set "inv=0"   else (      set /A "inv=(1<<31)^%~2"   )   call :floatAdd "%~1" "%inv%" "inv"   endlocal & set "%~3=%inv%"   goto :eof``
But i think this time i won't change the source above,
as it doesn't solve the whole problem, and
as the solution of the problem i plan to use seems to work without changing this function.

penpen

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

Hi penpen,

For give a sense at these functions (and test these functions) i have realized a "Plasma" effect.

This is an effect that can show error on visive method. But is nice to look and the work on this is more motivating (at least for me)

Since there is some my workaround on the complete code i don't know if this work.

plasma.cmd (use the ieee754 work):

Code: Select all

``@echo off& setlocal EnableDelayedExpansion&Goto :Init_System:: developed on windows 7 32bit. :: Use Lucida console 5 for best view:Main  call :create_palette  set /a e=Lenp/2  for /L %%y in (-30,1,30) do (    call :str2float "%%y" "fy"    :: newy=fy/8    call :floatMul "!fy!" "0x3E000000" newy    call :float2str "!newy!" "newy"    call :sin2 "!newy!" siny    call :str2float "!siny!" "fy"    call :str2float "!e!" "fe"    call :floatMul "!fy!" "!fe!" y1    call :float2str "!y1!" "y1"    :: get integer part    set app=!y1:*.=!    for %%a in (!app!) do set app=!y1:.%%a=!    if "!app!"=="." set app=0    set /a iy=e+!app!    for /L %%x in (-60,1,60) do (      call :str2float "%%x" "fx"      call :floatMul "!fx!" "0x3E000000" newx      call :float2str "!newx!" "newx"      call :sin2 "!newx!" sinx      call :str2float "!sinx!" "fx"      call :str2float "!e!" "fe"      call :floatMul "!fx!" "!fe!" x1      call :float2str "!x1!" "x1"      :: get integer part      set app=!x1:*.=!      for %%a in (!app!) do set app=!x1:.%%a=!      if "!app!"=="." set app=0      set /a ix=e+!app!       set /a "c=(ix+iy)/2"      call :plot !c!    )   echo(  )Goto :EndMain:sin2 %1=x radiants   set x=%~1   if "%x:~0,1%"=="-" (     set r=-1     set x=!x:~1!   ) else (     set r=1   )   rem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880 - x^2 * 1/39916800 )))))   call :str2float "%x%" "fx"   :: 0x40490FDB=3.14159265....   call :floatSub "%fx%" "0x40490FDB" "tx"   if !tx! gtr 0 set /A fx=tx, r=-r   call :floatMul "%fx%"       "%fx%"       "fxx"   call :floatMul "%fxx%"      "0x32D7322B" "fsinp"   call :floatSub "0x3638EF1D" "%fsinp%"    "fsinp2"   call :floatMul "%fxx%"      "%fsinp2%"   "fsinp3"   call :floatSub "0x39500D01" "%fsinp3%"   "fsinp4"   call :floatMul "%fxx%"      "%fsinp4%"   "fsinp5"   call :floatSub "0x3C088889" "%fsinp5%"   "fsinp6"   call :floatMul "%fxx%"      "%fsinp6%"   "fsinp7"   call :floatSub "0x3E2AAAAB" "%fsinp7%"   "fsinp8"   call :floatMul "%fxx%"      "%fsinp8%"   "fsinp9"   call :floatSub "0x3F800000" "%fsinp9%"   "fsinp10"   call :floatMul "%fx%"       "%fsinp10%"  "fsin"   if !r! lss 0 set /A "fsin=(1<<31)^fsin"   call :float2str "%fsin%" "sin"endlocal & set "%~2=%sin%"goto :eof:plot %1 call :color !p[%1]:~0,2! !p[%1]:~-1!goto :eof::manual palette:create_palette %1  set p=0  For %%p in (04 4C cE EA A2 21 15 50) do (      set "p[!p!]=%%p°" & set /a p+=1    set "p[!p!]=%%p±" & set /a p+=1    set "p[!p!]=%%p²" & set /a p+=1    set "p[!p!]=%%pÛ" & set /a p+=1  )  set /a p-=1  set Lenp=!p!goto :eofGoto :EndMain:: ( Begin Color Function:color    (echo %~2\..\'    ) > \$\$\$.color.txt && findstr /a:%~1 /f:\$\$\$.color.txt "."    Shift    Shift    If ""=="%~1" Goto :Eof   goto :color:: ) End color Fuction:Init_system  for /F "tokens=1,2 delims=#" %%a in ('"prompt #\$H#\$E# & echo on & for %%b in (1) do rem"') do (  set "DEL=%%a")    <nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%" > "'"Goto :Main:EndMain  :: Clearing all garbage  del 'Goto :Eof``

EDIT:
This use the code of ieee 754. On first post. Must merge.

Than the other change is the FloatSub.

This is my patch:

Code: Select all

``:floatSub::   %~1 minuend float in int coding::   %~2 subtrahend float in int coding::   %~3 resulting float in int coding   setlocal   rem echo sub=%1 %2   rem my temp patch   if "%~2"=="0" endlocal & set "%~3=%~1" & goto :eof   set /A "inv=(1<<31)^%~2"   rem echo inv = %inv%   call :floatAdd "%~1" "%inv%" "inv"   endlocal & set "%~3=%inv%"   goto :eof``

or can use the bugfix of penpen. But I have not tested:

Code: Select all

``:floatSub::   %~1 minuend float in int coding::   %~2 subtrahend float in int coding::   %~3 resulting float in int coding   setlocal   set /A "value=%~2"   if "%value%" == "0" (      set "inv=0"   else (      set /A "inv=(1<<31)^%~2"   )   call :floatAdd "%~1" "%inv%" "inv"   endlocal & set "%~3=%inv%"   goto :eof``

Sorry for this pieces of code, but this is working progress.

I will post the complete code in the other thread as soon possible.

einstein1969
Last edited by einstein1969 on 05 Jun 2014 19:55, edited 1 time in total.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

### Re: (nearly) ieee 754 floating point single precisition

It doesn't work as it is missing code...

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

### Re: (nearly) ieee 754 floating point single precisition

I have removed some bugs, converted the functions to macros, and split the source into two files:
- floaty.bat (the test cases; the source is at the bottom of this post)
- loadFloat.bat (that contains the macros)

So if you want to use the float functions in your batch file you only need to call "loadFloat.bat" once
and then just use the macros; make sure the extensions are enabled (default on most systems):

Code: Select all

``@echo offsetlocal enableExtensions:: load all macros, and exit if it has failed for whatever reasonscall "loadFloat.bat"if errorLevel 1 exit /b 1:: use the macros (names are similar to the function names)for %%a in (operand1 operand2 result string) do set "%%~a="%\$str2float% "10" operand1%\$str2float% "4"  operand2%\$floatAdd%  "%operand1%" "%operand2%" result%\$float2str% "%result%" stringecho("10" + "4" = "%string%"%\$floatSub%  "%operand1%" "%operand2%" result%\$float2str% "%result%" stringecho("10" - "4" = "%string%"%\$floatMul%  "%operand1%" "%operand2%" result%\$float2str% "%result%" stringecho("10" * "4" = "%string%"endlocal``

If you want to read the source (more easily), this "toSource.bat" may help:

Code: Select all

``@echo offsetlocal enableExtensions disableDelayedExpansioncall loadFloat.bat2>nul md "macros"for %%a in (str2float float2str floatAdd floatSub floatMul intToHex) do (   (      set "firstLine=true"      for /F "tokens=1* delims=:" %%b in ('set \$%%~a ^| findstr /N "^"') do (         if defined firstLine (            set "firstLine="            for /F "tokens=1* delims==" %%d in ("%%c") do (               set line=%%~e               echo(            )         ) else (            set line=%%~c         )         setlocal enableExtensions enableDelayedExpansion            set "line=!line:%%=%%%%!"            echo(!line!         endlocal      )   ) > "macros\%%~a.txt")endlocal``

This "floaty.bat" contains the test cases (exceeded the maximum number of allowed characters: 60000):

Code: Select all

``@echo offsetlocal enableExtensions  disableDelayedExpansioncall loadFloat.batif errorLevel 1 (set error=true)if defined error exit /b 1call :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(7FFFFFFF)    "call :floatTest "+NaN(FFFFFFFF)    "call :floatTest "-NaN(FFFFFFFF)    "call :floatTest "+NaN(FF83FFFF)    "call :floatTest "-NaN(FF83FFFF)    "call :floatTest "+NaN(FF83FFFF)    "call :floatTest "-NaN(FF83FFFF)    "call :floatTest "inf               "call :floatTest "+inf              "call :floatTest "-inf              "call :floatTest "0.0               "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       "echo(call :floatTest Add "45.0000" "-45.3000"call :floatTest Add "100" "0.006"call :floatTest Add "1.4E-45" "1.1754942E-38"call :floatTest Add "1.4E-45" "1.4E-45"call :floatTest Add "1" "2"echo(call :floatTest Sub "100" "0.006"call :floatTest Sub "1.4E-45" "1.1754942E-38"call :floatTest Sub "1.4E-45" "1.4E-45"call :floatTest Sub "1" "2"echo(call :floatTest Mul "100" "0.1"call :floatTest Mul "100" "0.05"call :floatTest Mul "100" "0.005"call :floatTest Mul "1.4E-45" "1"call :floatTest Mul "2.8E-45" "0.5"endlocalendlocalgoto :eof:floatTest (overloaded)::::   one arguments version: converts the string to a float and back, displaying the results::   %~1 float string::::   three arguments version: performs operand1 operator operand2, displays the result in hex/string::   %~1 float operator in { "add", "sub", "mul" }  (other operators are ignored)::   %~2 float string operand2::   %~3 float string operand1::   setlocal enableDelayedExpansion   set "op=%~1"   set "A=%~2"   set "B=%~3"   if %2. == . (      for %%a in ("float", "hex", "string") do set "%%~a="      %\$str2float% "%~1%"    float      %\$intToHex%  "!float!" hex      %\$float2str% "!float!" string      echo(!hex! ^<-- "%~1" --^> "!string!"   ) else (      for %%a in ("op", "value1", "value2", "float1", "float2", "float3", "hex1", "hex2", "hex3", "string1") do set "%%~a="      set "op[add]=+"      set "op[sub]=-"      set "op[mul]=*"      set "op=!op[%~1]!"      set "value1=%~2"      set "value2=%~3"      %\$str2float% "!value1!" "float1"      %\$str2float% "!value2!" "float2"      if        /I "%~1" == "add" (         %\$floatAdd% "!float1!" "!float2!" "float3"      ) else if /I "%~1" == "sub" (         %\$floatSub% "!float1!" "!float2!" "float3"      ) else if /I "%~1" == "mul" (         %\$floatMul% "!float1!" "!float2!" "float3"      ) else (         endlocal         goto :eof      )      %\$intToHex% "!float1!" "hex1"      %\$intToHex% "!float2!" "hex2"      %\$intToHex% "!float3!" "hex3"      %\$float2str% "!float3!" "string1"      echo !value1! !op! !value2! = !float1! !op! !float2! == !hex1! !op! !hex2! == !hex3! == !float3! == !string1!   )   endlocal   goto :eof``

penpen

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

Hi penpen,

very nice work but the macro version is slower...

This example for execute the code about 3-5X faster.

Code: Select all

``@echo offsetlocal enableExtensions:: load all macros, and exit if it has failed for whatever reasonscall loadfloat.cmdif errorLevel 1 exit /b 1:: use the macros (names are similar to the function names)for %%a in (operand1 operand2 result string) do set "%%~a="(setlocal EnableDelayedExpansion   set \$str2float=   set \$floatAdd=   set \$float2str=   set \$floatSub=   set \$floatMul=   set \$intToHex=   rem set |more   for /F "eol== delims==" %%f in ('set') do set "%%f="   >t0.\$\$\$.tmp echo !time!   for /L %%N in (1,1,100) do (      %\$str2float% "10" operand1      %\$str2float% "4"  operand2      %\$floatAdd%  "%operand1%" "%operand2%" result      %\$float2str% "%result%" string      rem echo("10" + "4" = "%string%"      %\$floatSub%  "%operand1%" "%operand2%" result      %\$float2str% "%result%" string      rem echo("10" - "4" = "%string%"      %\$floatMul%  "%operand1%" "%operand2%" result      %\$float2str% "%result%" string      rem echo("10" * "4" = "%string%"   )endlocal)<t0.\$\$\$.tmp set /p "t0="for /F "tokens=1-8 delims=:.," %%a in ("%t0: =0%:%time: =0%") do set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000"echo elapsed cs : %a%del t0.\$\$\$.tmpendlocal``

And for DIVISION why (for the moment) not implement Newton's Method for finding the reciprocal of a floating point number for division?

- http://en.wikipedia.org/wiki/Fast_inverse_square_root Fast inverse square root the square of this is the reciprocal!
- http://homepage.cs.uiowa.edu/~jones/bcd/divide.html Reciprocal Multiplication, a tutorial

einstein1969
Last edited by einstein1969 on 20 Aug 2014 16:25, edited 1 time in total.

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

foxidrive wrote:It doesn't work as it is missing code...

Hi foxidrive,

With the new code i have rewritten the plasma with new gradient.

Code: Select all

``@echo off& setlocal EnableDelayedExpansion&Goto :Init_System:Main  :: load all macros, and exit if it has failed for whatever reasons  call loadfloat.cmd  if errorLevel 1 exit /b 1  call :create_palette  set /a e=Lenp/2  for /L %%y in (-30,1,30) do (    %\$str2float% "%%y" fy    :: newy=fy/8                                1/4=0x3E800000  1/8=0x3E000000    rem call :floattestMul2 "1" "0.25" newy    %\$floatMul% "!fy!" "0x3E800000" newy    %\$float2str% "!newy!" newy    call :sin2 "!newy!" siny    %\$str2float% "!siny!" fy    %\$str2float% "!e!" fe    %\$floatMul% "!fy!" "!fe!" y1    %\$float2str% "!y1!" y1    :: get integer part    set app1=!y1:*e-=!    if not "!y1!"=="!app1!" (set app=0) else (        set app=!y1:*.=!        for %%a in (!app!) do set app=!y1:.%%a=!      )    if "!app!"=="." set app=0    set /a iy=e+!app!    for /L %%x in (-60,1,60) do (set t0=!time!      %\$str2float% "%%x" "fx"      %\$floatMul% "!fx!" "0x3E800000" newx      %\$float2str% "!newx!" "newx"set t1=!time!      call :sin2 "!newx!" sinxset t2=!time!      %\$str2float% "!sinx!" fx      %\$str2float% "!e!" fe      %\$floatMul% "!fx!" "!fe!" x1      %\$float2str% "!x1!" x1set t3=!time!      :: get integer part      set app1=!x1:*e-=!      if not "!x1!"=="!app1!" (set app=0) else (        set app=!x1:*.=!        for %%a in (!app!) do set app=!x1:.%%a=!      )      if "!app!"=="." set app=0      set /a ix=e+!app!       set /a "c=(ix+iy)/2"      call :plot !c!    )   echo(  )Goto :EndMain:sin2 %1=x radiants   set x=%~1   if "%x:~0,1%"=="-" (     set r=-1     set x=!x:~1!   ) else (     set r=1   )   rem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880 - x^2 * 1/39916800 )))))   %\$str2float% "%x%" "fx":sin2_PI   :: 0x40490FDB=3.14159265....   %\$floatSub% "%fx%" "0x40490FDB" "tx"   if !tx! gtr 0 (set /A fx=tx, r=-r) else goto :sin2_cont   goto :sin2_PI:sin2_cont   %\$floatMul% "%fx%"       "%fx%"       "fxx"   %\$floatMul% "%fxx%"      "0x32D7322B" "fsinp"   %\$floatSub% "0x3638EF1D" "%fsinp%"    "fsinp2"   %\$floatMul% "%fxx%"      "%fsinp2%"   "fsinp3"   %\$floatSub% "0x39500D01" "%fsinp3%"   "fsinp4"   %\$floatMul% "%fxx%"      "%fsinp4%"   "fsinp5"   %\$floatSub% "0x3C088889" "%fsinp5%"   "fsinp6"   %\$floatMul% "%fxx%"      "%fsinp6%"   "fsinp7"   %\$floatSub% "0x3E2AAAAB" "%fsinp7%"   "fsinp8"   %\$floatMul% "%fxx%"      "%fsinp8%"   "fsinp9"   %\$floatSub% "0x3F800000" "%fsinp9%"   "fsinp10"   %\$floatMul% "%fx%"       "%fsinp10%"  "fsin"   if !r! lss 0 set /A "fsin=(1<<31)^fsin"   %\$float2str% "%fsin%" "sin"   set "%~2=%sin%"goto :eof:plot %1 call :color !p[%1]:~0,2! !p[%1]:~-1!goto :eof::manual palette, best color add,  rif. http://en.wikipedia.org/wiki/Web_colorsremrem 1 -> 2 3 4 5 6 9rem 2 -> 1 3 4 5 6 Arem 3 -> 1 2 4 5 6 9 A Brem 4 -> 1 2 3 5 6 Crem 5 -> 1 2 3 4 6 9 Drem 6 -> Erem 9 -> 1 3 5rem A -> 2 3 6rem B -> 3rem C -> 4 5 6rem D -> 5rem E -> 6:create_palette %1  set p=0  rem For %%p in (04 4C cE EA A2 21 15 50) do (  For %%p in (04 4C c5 53 39 91 15 50) do (      set "p[!p!]=%%p°" & set /a p+=1    set "p[!p!]=%%p±" & set /a p+=1    set "p[!p!]=%%p²" & set /a p+=1    set "p[!p!]=%%pÛ" & set /a p+=1  )  set /a p-=1  set Lenp=!p!goto :eofGoto :EndMain:: ( Begin Color Function:color    (echo %~2\..\'    ) > \$\$\$.color.txt && findstr /a:%~1 /f:\$\$\$.color.txt "."    Shift    Shift    If ""=="%~1" Goto :Eof   goto :color:: ) End color Fuction:Init_system  for /F "delims==" %%f in ('set') do if /i not "%%f"=="Path" set "%%f="  for /F "tokens=1,2 delims=#" %%a in ('"prompt #\$H#\$E# & echo on & for %%b in (1) do rem"') do (  set "DEL=%%a")    <nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%" > "'"Goto :Main:EndMain  :: Clearing all garbage  del 'Goto :Eof``

It's slower than precedent, but it's possible use the trick of "empty the environment" and the trick of "while in a for loop" for achieve a 3-5X faster execute.

EDIT:

this is little optimized code which show how to maintain the env empty even with a call at subroutine.

Code: Select all

``@echo off& setlocal EnableDelayedExpansion&Goto :Init_System:Main  :: load all macros, and exit if it has failed for whatever reasons  call loadfloat.cmd  if errorLevel 1 exit /b 1  call :create_palette  set /a e=Lenp/2  for /L %%y in (-16,1,16) do (    %\$str2float% "%%y" fy    :: newy=fy/8                                1/4=0x3E800000  1/8=0x3E000000    rem call :floattestMul2 "1" "0.25" newy    %\$floatMul% "!fy!" "0x3E800000" newy    %\$float2str% "!newy!" newy    call :sin2 "!newy!" siny    %\$str2float% "!siny!" fy    %\$str2float% "!e!" fe    %\$floatMul% "!fy!" "!fe!" y1    %\$float2str% "!y1!" y1    :: get integer part    set app=!y1:*e-=!    if not "!y1!"=="!app!" (set app=0) else (        set app=!y1:*.=!        for %%a in (!app!) do set app=!y1:.%%a=!      )    if "!app!"=="." set app=0    set /a iy=e+!app!    set app=    for /L %%x in (-16,1,16) do (      %\$str2float% "%%x" "fx"      %\$floatMul% "!fx!" "0x3E800000" newx      %\$float2str% "!newx!" "newx"      call :sin2 "!newx!" sinx      %\$str2float% "!sinx!" fx      %\$str2float% "!e!" fe      %\$floatMul% "!fx!" "!fe!" x1      %\$float2str% "!x1!" x1      :: get integer part      set app=!x1:*e-=!      if not "!x1!"=="!app!" (set app=0) else (        set app=!x1:*.=!        for %%a in (!app!) do set app=!x1:.%%a=!      )      if "!app!"=="." set app=0      set /a ix=e+!app!      set app=       set /a "c=(ix+iy)/2"      call :plot !c!    )   echo(  )Goto :EndMainrem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880 - x^2 * 1/39916800 ))))):sin2 %1=x radiants   call loadfloat.cmd(   set \$str2float=   set \$floatAdd=   set \$float2str=   set \$floatSub=   set \$floatMul=   set \$intToHex=   rem set & pause   set x=%~1   if "!x:~0,1!"=="-" (     set r=-1     set x=!x:~1!   ) else (     set r=1   )   %\$str2float% "!x!" "fx"   :: PI=3.14159265....=0x40490FDB   set break=   for /L %%I in (1,1,10) do if not defined break (      %\$floatSub% "!fx!" "0x40490FDB" tx      if !tx! gtr 0 (set /A fx=tx, r=-r) else set break=true   )   set break=   %\$floatMul% "!fx!"       "!fx!"       fxx   %\$floatMul% "!fxx!"      "0x32D7322B" fsint   %\$floatSub% "0x3638EF1D" "!fsint!"    fsint   %\$floatMul% "!fxx!"      "!fsint!"    fsint   %\$floatSub% "0x39500D01" "!fsint!"    fsint   %\$floatMul% "!fxx!"      "!fsint!"    fsint   %\$floatSub% "0x3C088889" "!fsint!"    fsint   %\$floatMul% "!fxx!"      "!fsint!"    fsint   %\$floatSub% "0x3E2AAAAB" "!fsint!"    fsint   %\$floatMul% "!fxx!"      "!fsint!"    fsint   %\$floatSub% "0x3F800000" "!fsint!"    fsint   %\$floatMul% "!fx!"       "!fsint!"    fsin   set fsint=   set fx=   set fxx=   if !r! lss 0 set /A "fsin=(1<<31)^fsin"   %\$float2str% "!fsin!" sin   set "%~2=!sin!"   set fsin=   set sin=goto :eof ):plot %1 call :color !p[%1]:~0,2! !p[%1]:~-1!goto :eof::manual palette, best transient color,  rif.http://en.wikipedia.org/wiki/Web_colorsremrem 1 -> 2 3 4 5 6 9rem 2 -> 1 3 4 5 6 Arem 3 -> 1 2 4 5 6 9 A Brem 4 -> 1 2 3 5 6 Crem 5 -> 1 2 3 4 6 9 Drem 6 -> Erem 9 -> 1 3 5rem A -> 2 3 6rem B -> 3rem C -> 4 5 6rem D -> 5rem E -> 6:create_palette %1  set p=0  rem For %%p in (04 4C cE EA A2 21 15 50) do (  For %%p in (04 4C c5 53 39 91 15 50) do (      set "p[!p!]=%%p°" & set /a p+=1    set "p[!p!]=%%p±" & set /a p+=1    set "p[!p!]=%%p²" & set /a p+=1    set "p[!p!]=%%pÛ" & set /a p+=1  )  set /a p-=1  set Lenp=!p!goto :eofGoto :EndMain:: ( Begin Color Function:color    (echo %~2\..\'    ) > \$\$\$.color.txt && findstr /a:%~1 /f:\$\$\$.color.txt "."    Shift    Shift    If ""=="%~1" Goto :Eof   goto :color:: ) End color Fuction:Init_system  for /F "delims==" %%f in ('set') do if /i not "%%f"=="Path" set "%%f="  for /F "tokens=1,2 delims=#" %%a in ('"prompt #\$H#\$E# & echo on & for %%b in (1) do rem"') do (  set "DEL=%%a")    <nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%" > "'"Goto :Main:EndMain  :: Clearing all garbage  del 'Goto :Eof``

EDIT: I have added code optimized for performance.

einstein1969

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

### Re: (nearly) ieee 754 floating point single precisition

einstein1969 wrote:
foxidrive wrote:It doesn't work as it is missing code...

Hi foxidrive,

With the new code i have rewritten the plasma with new gradient.

einstein1969

It doesn't work here - generates an error and aborts.

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

Can you try the last version? I have written in the other thread. It's simple to debug. Post output in the other thread.

thanks!

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

Hi penpen,

After a long time I'm studying this project of yours. I imagine you've forgotten a bit how it works by now. But if you want to help me understand it at least a little, I will be truly grateful.

I'm starting to study how what you did works, also getting help from what I find on the web. But there's so much stuff I'm missing. Then you have to consider that I don't have strong understanding skills and therefore it takes me a very long time to understand.

First of all I'm studying the function that takes a string and transforms it into ieee754 using 32bit. The "str2float"

I still don't know how the complex operation is accomplished. I'm trying to create a simpler one just to understand how it works.

I have decided for the moment to neglect the whole part that deals with the inf, nan, hex values.

I took the comments you put in the procedure, to understand the steps. But I have a lot of difficulty.
• divide into parts: sPart * iPart.fPart * 10^^ePart
I understood this part.

• set sign flag(s)
I understood this part.

• detect NaN, inf and hex format
I skipped this part for now.

• normalize to: sPart * 0.significand * 10^ePart, 0.significand >= 0.1 AND detect 0.0
I'm having trouble with this part.

first of all what do you mean here: "0.significand >= 0.1"?
this is the code that studing at moment:

Code: Select all

``````   ) else (
for /F "tokens=* delims= " %%a in ("!iPart:0= !") do @set "iPartP=%%~a"
for /F "tokens=* delims= " %%a in ("!fPart:0= !") do @set "fPartP=%%~a"

if "!iPartP!!fPartP!" == "" (
>nul set /A "float=s"
) else (
if defined iPartP (
set "iPartP=!iPartP: =0!"
set "fPartP=!fPart!"
set "string= !iPartP!"
set "op=+"
) else if defined fPartP (
set "fPartP=!fPartP: =0!"
for %%a in (!fPartP!) do @set "string= !fPart:%%a=!"
set "op=-"
)

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!"
>nul set /A "ePart!op!=%%a"
)

set "significand=!iPartP!!fPartP!"
set "iPartP="
set "fPartP="
``````
here I understand that you have to calculate the number of digits to move the decimal point. And then you add them or subtract them from the exponent.
And then join the integer part and the fractional part together.

Did I get it right?

if the number is "10.3" , significand=103 and ePart=2 ?

if the number is "99.3", significand=993 and ePart=2 ?

if the number is "0.03", significand=3 and ePart=-1 ?
Last edited by einstein1969 on 23 May 2024 06:53, edited 1 time in total.

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

This is the very simplified version I'm working on:

Code: Select all

``````:str2float_very_simple string var_float

set "string=%~1"
set "string= !string: =!"

rem for now I only consider numbers without epart
set "ePart=0"

set "fPart=!string:*.=!"
if "!string!" == "!fPart!" ( set "fPart=0" ) else for %%a in ("!fPart!") do @set "string=!string:.%%~a=!"

set "sPart="
if "!string:~1,1!" == "-" (
set "iPart=!string:~2!"
set "sPart=-"
) else if "!string:~1,1!" == "+" (
set "iPart=!string:~2!"
) else set "iPart=!string:~1!"

rem echo string=%1 s=!spart! i=!ipart! f=!fpart!

if defined sPart ( set /A "s=1<<31" ) else ( set "s=0" )

rem echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart!

::   normalize to: sPart * 0.significand * 10^ePart, 0.significand >= 0.1
::   AND
::   detect 0.0

set "float="

for /F "tokens=* delims= " %%a in ("!iPart:0= !") do set "iPartP=%%~a"
for /F "tokens=* delims= " %%a in ("!fPart:0= !") do set "fPartP=%%~a"

echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart! iPartP=[!iPartP!] fPartP=[!fPartP!] ePart=!ePart!

if "!iPartP!!fPartP!" == "" (
>nul set /A "float=s"
) else (
if defined iPartP (
set "iPartP=!iPartP: =0!"
set "fPartP=!fPart!"
set "string= !iPartP!"
set "op=+"
) else if defined fPartP (
set "fPartP=!fPartP: =0!"
for %%a in (!fPartP!) do set "string= !fPart:%%a=!"
set "op=-"
)

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!"
>nul set /A "ePart!op!=%%a"
)

echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart! iPartP=[!iPartP!] fPartP=[!fPartP!] ePart=!ePart!

set "significand=!iPartP!!fPartP!"
set "iPartP="
set "fPartP="

echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart! significand=!significand! ePart=!ePart!

)

goto :eof
``````

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

### Re: (nearly) ieee 754 floating point single precisition

Yes, you got it right so far.

If i remember right, then the basic idea is to start with a number string in scientific notation,
transform that into a decimal floating point representation with exponent to base ten (sign, decimal number, exponent to base 10),
transform that into a decimal floating point representation with exponent to base two (sign, decimal number, exponent to base 2) and
normalize that value such that 1 <= decimal number (d) < 2,
so that we can apply the following algorithm (in c-like notation and ignoring rounding here) to calculate the binary number representation (f):

Code: Select all

``````// The following is kinda like f := floor(d * 2^24):
f = 0;
for (int i = 0; i <= 24; ++i) {
if (d >= 1) {
f = 2 * (f+1);
d = 2 * (d-1);
} else {
f = 2 * f;
d = 2 * d;
}
}

``````
Since batch is limited, i added some extra steps (to ensure beeing in a defined state) and used an unusual high-low number representation, which makes the code harder to read.

penpen

einstein1969
Expert
Posts: 947
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

### Re: (nearly) ieee 754 floating point single precisition

Thanks a lot. Yes, in fact, the code I am reading is very difficult and it will take me a long time.

You can give me an example with a "number" because it's not yet clear to me:

"If i Remember Right, then the basic idea is to start with a number string in scientific notation" Example .....
"Transform that into a decimal floating point represement with exponent to base ten (sign, decimal number, exponent to base 10)" Example .....
Transform that into a decimal floating point represement with exponent to base Two (sign, decimal number, exponent to base 2) Example .....

Then this part how to do it?
"normalize that value such That 1 <= decimal number (D) <2" Example .....

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

### Re: (nearly) ieee 754 floating point single precisition

Then this part how to do it?
"normalize that value such That 1 <= decimal number (d) <2" Example .....
After (finally) looking at the code, I would say (in case i didn't msiread my code), that i used a strlength algorithm on d, to shift the first non 0 digit at the first place of after the decimal seperator, such that 0.1 < d < 1.
Then I shift d left by one decimal digit, such that 1 <= d < 10.
Then if needed, I divide d by 2 until 1 <= d < 2.

Here is a short example:

Code: Select all

``````"-2469.1356E-9"
= -2469.1356 * 10^-9                        ;  iPart=2469; fPart= 1356; ePart=-9
; (strlen algorithm)
= -0.24691356 * 10^-5                       ;  sPart=-; significand=24691356; ePart=-5 (normalized to 0.1 <= 0.24691356 < 1, in order to avoid case disctinctions)
= -0.24691356000000000 * 10^-5              ;  sPart=-; significand=24691356000000000; ePart=-5 (extend to 17 digits; more wouldn't be noticed anyways)
= -2.4691356000000000 * 10^-6               ;  sPart=-; high=246913560; low=00000000; ePart=-6 (high: 9 digits, low part 8 digits)
= -2.4691356000000000 * 2^-6  * 5^-6        ;  sPart=-; high=246913560; low=00000000; e_2=-6; ePart=-6
;  divide h.ighlow by 2 (updating the e_2 value) until 1 <= h.ighlow < 2
= -1.2345678000000000 * 2^-5  * 5^-6        ;  sPart=-; high=123456780; low=00000000; e_2=-5; ePart=-6
= -0.12345678000000000 * 2^-4  * 5^-5
= -1.9753084800000000 * 2^-8  * 5^-5        ;  sPart=-; high=197530848; low=00000000; e_2 =-8; ePart=-5
= ...
= -1.2945381654528000 * 2^-19 * 5^0         ;  sPart=-; high=129453816; low=54528000; e_2=-19

==> s = 1
and e = 127-19 = 108 = 1101100_2
and f = floor(1.2945381654528000 * 2^24) = 21718746 = 101001011011001101101101_2
e != 255 ==> normalized number
==> ieee_value = [s (1 bit), e (8 bit), f without leading 1 (23 bit)] = [1, 01101100, 01001011011001101101101]_2 = 10110101101001011011001101101101_2 = -1239043219
``````
Sidenote:
If the number were denormalized, then no bit is removed (= the highest 23 bits are used to encode the ieee_value).

penpen