# Lazarus

## Programming => General => Topic started by: Skotty on April 04, 2020, 03:40:18 am

Title: Initialize Const Single based on raw hexadecimal value
Post by: Skotty 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?
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: winni 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
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: Skotty 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.
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: winni 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

Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: Thaddy 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
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: Thaddy 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?

Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: Skotty 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;

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

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
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.
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: BrunoK 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;
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),' ');
14. end.
Both i386+FPC 3.0.4 and x86_64+FPC 3.3.1
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: Skotty 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:

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 )
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: Thaddy 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.
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: BrunoK 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).
Title: Re: Initialize Const Single based on raw hexadecimal value
Post by: ASerge 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