Recent

Author Topic: Initialize Const Single based on raw hexadecimal value  (Read 2048 times)

Skotty

  • New Member
  • *
  • Posts: 13
Initialize Const Single based on raw hexadecimal value
« on: April 04, 2020, 03:40:18 am »
I have the following use-case:
Free Pascal's MaxSingle from 'math' unit is actually not accurately the max Single value. For this I want to define a new constant, based on the actual hex-value that defines the max Single size.

What I would want to do is:
Code: Pascal  [Select][+][-]
  1. const
  2.   MaxSingle: Single = $7f7fffff; // Do NOT treat as Integer!
Unfortunately this treats my hexadecimal value as Integer, and converts it into a Float. However, I want to tell the compiler not to do any conversions, but take the hexadecimal value as it comes, bit for bit.

A workaround I found so far is:
Code: Pascal  [Select][+][-]
  1. const
  2.   MaxSingleAsInt: Int32 = $7f7fffff;
  3. var
  4.   MaxSingle: Single absolute MaxSingleAsInt;

Alternatively inside of a procedure one could do:
Code: Pascal  [Select][+][-]
  1. Int32(MaxSingle) := $7f7fffff;
But this does not help/work with actual global constants to be defined.

How would I achieve to set the Single value directly, without any of these workarounds?
« Last Edit: April 04, 2020, 03:43:03 am by Skotty »

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Initialize Const Single based on raw hexadecimal value
« Reply #1 on: April 04, 2020, 03:44:38 am »
Hi!

You tested a lot of possibilities - but not the right one:

Code: Pascal  [Select][+][-]
  1. MyMaxSingle = single( $7f7fffff);  

Keep on investigating!

Winni

Skotty

  • New Member
  • *
  • Posts: 13
Re: Initialize Const Single based on raw hexadecimal value
« Reply #2 on: April 04, 2020, 03:48:50 am »
Thanks for the answer. Unfortunately using the Single( ) typecast around that hex-value does only just convert it from an Integer, too. Based on your example:
Quote
const
  MyMaxSingle = single( $7f7fffff);
The output via Writeln( ) actually is 2.139095040E+09. However, this is because it treats it as Integer. The correct value must be 3.402823466E+38.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Initialize Const Single based on raw hexadecimal value
« Reply #3 on: April 04, 2020, 04:08:25 am »
Hi!

You think wrong about what you are doing.

$7f7fffff is an Integer and not a bitmask!

Why do you want to declare a const as bitmask and not just simple as

Code: Pascal  [Select][+][-]
  1. MyMaxSingle = 3.402823466E+38;

So from the point of pascal syntax the result with  2.139095040E+09 is correct.

And you dont need to create yourself such problems:

MaxSingle is already defined in the unit math.

Keep on hacking!

Winni


Thaddy

  • Hero Member
  • *****
  • Posts: 14164
  • Probably until I exterminate Putin.
Re: Initialize Const Single based on raw hexadecimal value
« Reply #4 on: April 04, 2020, 08:13:17 am »
Here's is how to get what you want, as well as an another option that shows the Pascal value:
Code: Pascal  [Select][+][-]
  1. uses sysutils;
  2. var
  3.  a:integer = $7f7fffff;
  4. begin
  5.    writeln($7f7fffff.ToSingle);// Pascal value using helper
  6.    writeln(PSingle(@a)^);     // The C like value (bitpattern) that you expect through a pointer dereference.
  7. end.
 
output:
Code: Bash  [Select][+][-]
  1.  2.139095040E+09
  2.  3.402823466E+38
This is actually documented!
See: https://wiki.freepascal.org/User_Changes_3.0#Casting_integer_variables_to_floating_point
« Last Edit: April 04, 2020, 08:43:28 am by Thaddy »
Specialize a type, not a var.

Thaddy

  • Hero Member
  • *****
  • Posts: 14164
  • Probably until I exterminate Putin.
Re: Initialize Const Single based on raw hexadecimal value
« Reply #5 on: April 04, 2020, 08:56:32 am »
Better, using the docs (memory correct, but not complete):
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. program f;
  3. uses sysutils;
  4. type
  5.  SingleCast = record value:single;end;
  6. var
  7.  a:integer = $7f7fffff;
  8. begin
  9.    writeln($7f7fffff.ToSingle);  //Pascal value helper
  10.    writeln(PSingle(@a)^);        //Bit pattern (C style) <=== this is what I use.
  11.    writeln(SingleCast(a).value); //Record cast, see docs
  12. end.
 

(Side note: I really do not like that change in behavior. Wonder what Delphi does...anyway above two options extra..)
Oh, and maybe (in mode objfpc):
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$modeswitch typehelpers}
  2. program f;
  3. uses sysutils;
  4. type
  5.   TIntegerHelperEx = type helper(TintegerHelper) for integer
  6.      function AsSingle:single;inline; // as opposed to ToSingle this uses bitpattern
  7.   end;
  8.  
  9.   function TIntegerHelperEx.AsSingle:single;
  10.   begin
  11.     Result := PSingle(@self)^;//This is Pascal syntax equal to a C++ reinterpret cast
  12.   end;
  13.  
  14. begin
  15.  writeln($7f7fffff.AsSingle);
  16. end.
Enough options?

« Last Edit: April 04, 2020, 09:38:44 am by Thaddy »
Specialize a type, not a var.

Skotty

  • New Member
  • *
  • Posts: 13
Re: Initialize Const Single based on raw hexadecimal value
« Reply #6 on: April 04, 2020, 12:08:55 pm »
Edit: I found the right answer thanks to a friend. Winni was not so far off, but missed an important piece:
Code: Pascal  [Select][+][-]
  1. const
  2.   MyMaxSingle = Single(3.402823466E+38);
  3.   // or
  4.   MyMaxSingle: Single = 3.402823466E+38;
Defining it with the number requires at least to add the Single type so it is not interpreted as Extended.
Now the hex value of this is precisely 7F7FFFF.


Thanks for the answers so far.

@winni
Why do you want to declare a const as bitmask and not just simple as

Code: Pascal  [Select][+][-]
  1. MyMaxSingle = 3.402823466E+38;
Unfortunately defining it like in your example adds some rounding errors.

And you dont need to create yourself such problems:

MaxSingle is already defined in the unit math.
I wrote in the first post that FPC's MaxSingle isn't exactly the correct maximum for single point floats. See Wikipedia: https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Single-precision_examples



@Thaddy:
Thanks for your helpful examples.
The cast to a Record Type would be what comes closest to what I want, but unfortunately this seems not allowed when defining a Const.

About the approaches using functions: Unfortunately I am searching for a way to define it as real Const. Call it silly, but I am at this point curious how this can be done in FPC.
Unfortunately the Compiler does not allow me to define something like:
Code: Pascal  [Select][+][-]
  1. const
  2.   MaxSingle: Single = Int32($7f7fffff).AsBitMaskSingle;
Apparently it does not allow a function call in the initialization of Consts and Vars.

Sure I could just always call a function to output the value to me at the points I need it. But I am really curious how it can be done properly as a real constant value the compiler can then just insert at compile time.
« Last Edit: April 04, 2020, 12:25:12 pm by Skotty »

BrunoK

  • Sr. Member
  • ****
  • Posts: 452
  • Retired programmer
Re: Initialize Const Single based on raw hexadecimal value
« Reply #7 on: April 04, 2020, 12:56:11 pm »
@winni
Why do you want to declare a const as bitmask and not just simple as

Code: Pascal  [Select][+][-]
  1. MyMaxSingle = 3.402823466E+38;
Unfortunately defining it like in your example adds some rounding errors.
For me  winni's way work as expected see test program :
Code: Pascal  [Select][+][-]
  1. program pgmMaxSingle;
  2.  
  3. const
  4.   cMaxSingle1 = 3.402823466E+38;
  5.  
  6. var
  7.   vSingleH : dword = $7f7fffff;
  8.   vSingle  : single absolute vSingleH;
  9. begin
  10.   WriteLn('vSingleH = $7f7fffff ',vSingle, ' ', HexStr(vSingleH,8),' ');
  11.   vSingle := cMaxSingle1; // 3.402823466E+38;
  12.   WriteLn('vSingle := cMaxSingle1 ',vSingle, ' ', HexStr(vSingleH,8),' ');
  13.   ReadLn;
  14. end.
Both i386+FPC 3.0.4 and x86_64+FPC 3.3.1

Skotty

  • New Member
  • *
  • Posts: 13
Re: Initialize Const Single based on raw hexadecimal value
« Reply #8 on: April 04, 2020, 01:29:20 pm »
Your test program is correct so far. But there is a flaw in it:
It only is correct because you assign cMaxSingle1 to a Single variable before.
However if you want to do for example an equals check, it does not match any longer:

(add between Line 12 and 13 in your example)
Code: Pascal  [Select][+][-]
  1. WriteLn(cMaxSingle1 = vSingle);

If a constant names itself MaxSingle I as programmer want to expect this comparison to be TRUE. But without a Single( ) cast around cMaxSingle1 it outputs FALSE, because cMaxSingle1 internally is represented as Real type (see https://www.freepascal.org/docs-html/ref/refse9.html )

Thaddy

  • Hero Member
  • *****
  • Posts: 14164
  • Probably until I exterminate Putin.
Re: Initialize Const Single based on raw hexadecimal value
« Reply #9 on: April 04, 2020, 01:40:56 pm »
The absolute option that skotty proposed as working is also OK, You did not read his question.
« Last Edit: April 04, 2020, 02:32:36 pm by Thaddy »
Specialize a type, not a var.

BrunoK

  • Sr. Member
  • ****
  • Posts: 452
  • Retired programmer
Re: Initialize Const Single based on raw hexadecimal value
« Reply #10 on: April 04, 2020, 02:51:26 pm »
Your test program is correct so far. But there is a flaw in it:
It only is correct because you assign cMaxSingle1 to a Single variable before.
However if you want to do for example an equals check, it does not match any longer:
...
So just use your
Code: Pascal  [Select][+][-]
  1. const
  2.   MyMaxSingle = Single(3.402823466E+38);
that evaluates correctly.

The flaw is math.MaxSingle not being correctly defined. (And there are other similar problems around, re currency on x86_64).

ASerge

  • Hero Member
  • *****
  • Posts: 2212
Re: Initialize Const Single based on raw hexadecimal value
« Reply #11 on: April 04, 2020, 05:17:02 pm »
By the way, the latest version of Delphi defines MaxSingle as 340282346638528859811704183484516925440.0 which is a zero extension of the $7f7fffff number to 128 bits and converting the result to decimal, according to the IEEE 754 standard. Of course in a machine representation of 4 bytes the value does not differ from 340282346600000000000000000000000000000.0

 

TinyPortal © 2005-2018