RoboPro .rpp float calculation

Alles rund um TX(T) und RoboPro, mit ft-Hard- und Software
Computing using original ft hard- and software
Forumsregeln
Bitte beachte die Forumsregeln!
Gesperrt
vleeuwen
Beiträge: 1564
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

RoboPro .rpp float calculation

Beitrag von vleeuwen » 30 Sep 2019, 00:20

RoboPro stores a 48 bit float in the XML .rpp file as datatype=11.
and is using 3 values for this: value0, value1 and value2.
For example:
-285 is stored as value0= -24567 value1= -29056 value2= 0
285 is stored as value0= 8201 value1= -29056 value2= 0
0 is stored as value0= 2 value1= 0 value2= 0
-360 is stored as value0= -24567 value1= -19456 value2= 0
410 is stored as value0= 8201 value1= -13056 value2= 0
360 is stored as value0= 8201 value1= -19456 value2= 0

Can somebody clarified how this calculation (function f) is done in general?
result 48 bits float =f(value0, value1, value2)

vleeuwen
Beiträge: 1564
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: RoboPro .rpp float calculation

Beitrag von vleeuwen » 30 Sep 2019, 08:18

From RoboPro help:
The precision of arithmetic operations is 48 bits with a 32 bit mantissa. This corresponds to a precision of slightly more than 9 decimal digits.

But how to come from the value), value1, value2 to a C# or C/C++ Double type?

Has there been used the old Pascal 48-bits real type?
https://stackoverflow.com/questions/319 ... nt-integer
http://www.shikadi.net/moddingwiki/Turbo_Pascal_Real
No, this has a 40 bits mantissa.

Benutzeravatar
MasterOfGizmo
Beiträge: 2720
Registriert: 30 Nov 2014, 07:44

Re: RoboPro .rpp float calculation

Beitrag von MasterOfGizmo » 30 Sep 2019, 15:05

The MSB of value 0 ist the sign, the rest of value 0 is the exponent and value 1 and value 2 are the mantissa.
Arduino für fischertechnik: ftDuino http://ftduino.de, ftDuino32 http://ftduino.de/32

Benutzeravatar
MasterOfGizmo
Beiträge: 2720
Registriert: 30 Nov 2014, 07:44

Re: RoboPro .rpp float calculation

Beitrag von MasterOfGizmo » 30 Sep 2019, 15:43

value0= -24567 value1= -29056 value2= 0
value1 is -29056. This is unsigned 36480. Append value 2 which is 0 (shift 16 bits left and add value 2) gives 2390753280. Divide by 2^32 gives 0,556640625. Sign is -1 since value 0 (-24567) is negative.

Thus the mantissa is -0.556640625

Value 0 without sign is 8201. Subtract the exponent offset which seems to be 2^13 = 8192. The exponent thus is 8201 - 8192 = 9.

The result thus is -0.556640625 * 2^9 = -0.556640625 * 512 = -285

So value0= -24567 value1= -29056 value2= 0 is -285
Arduino für fischertechnik: ftDuino http://ftduino.de, ftDuino32 http://ftduino.de/32

vleeuwen
Beiträge: 1564
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: RoboPro .rpp float calculation

Beitrag von vleeuwen » 30 Sep 2019, 18:22

Zuletzt geändert von vleeuwen am 03 Okt 2019, 09:42, insgesamt 2-mal geändert.

vleeuwen
Beiträge: 1564
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: RoboPro .rpp float calculation

Beitrag von vleeuwen » 01 Okt 2019, 12:29

The result in C#.
Reverse engineering of data type 11 in the RoboPro .rpp XML serialization.
Based on: http://www.shikadi.net/moddingwiki/Turbo_Pascal_Real

Code: Alles auswählen

        public Double Convert(string val0, string val1, string val2)
        {
            Double result = Double.NaN;
            try
            {
                byte[] real48 = null;
                Int16 i0 = Int16.Parse(val0), i1 = Int16.Parse(val1), i2 = Int16.Parse(val2);
                byte[] bi0 = BitConverter.GetBytes(i0), bi1 =  BitConverter.GetBytes(i1), bi2 = BitConverter.GetBytes(i2);
                real48 = addByteToArray(bi0, bi1, bi2);
                //=======================================================
                Int32 exponent = ((real48[5] & 0x7F) * 0x100) + real48[4];// first 15 bits 
                exponent = exponent - 8192;  //8192= Math.Pow(2.0, 13) but has a double type;
                // Now Calculate the mantissa
                Double mantissa = 0.0, value = 1.0;
                // For Each Byte.
                for (int i = 3; i >= 0; i--)
                {
                    int startbit = 7;
                    //For Each Bit
                    for (int j = startbit; j >= 0; j--)
                    {
                        value = value / 2;// Each bit is worth half the next bit but we're going backwards.
                        if (((real48[i] >> j) & 1) == 1) mantissa += value; // add the value if bit set.
                    }
                }
                if (mantissa == 1.0 && real48[0] == 0) result = 0.0f;// Test for null value
                else
                {
                    if ((real48[5] & 0x80) == 0x80) // Sign 16th bit of value0 (byte 4and 5) check
                        mantissa = -mantissa;
                    result = mantissa * Math.Pow(2.0, exponent);
                }
            }
            catch (Exception e)
            {
                throw new System.Exception("Conversion error", e.InnerException);
            }
            return result;
        }
Supporting methode:

Code: Alles auswählen

       public byte[] addByteToArray(byte[] b0Array, byte[] b1Array, byte[] b2Array)
        {
            byte[] concat = null;
            if (b2Array.Length == 2 && b1Array.Length == 2 && b0Array.Length == 2)
            {
                concat = new byte[6];
                System.Buffer.BlockCopy(b2Array, 0, concat, 0, 2); 
                System.Buffer.BlockCopy(b1Array, 0, concat, 2, 2);  
                System.Buffer.BlockCopy(b0Array, 0, concat, 4, 2);
            }
            else
            { throw new System.ArgumentException("One of the parameter is not a 2 bytes value", "conversion error"); }
            return concat;

        }
Zuletzt geändert von vleeuwen am 03 Okt 2019, 09:44, insgesamt 4-mal geändert.

Benutzeravatar
MasterOfGizmo
Beiträge: 2720
Registriert: 30 Nov 2014, 07:44

Re: RoboPro .rpp float calculation

Beitrag von MasterOfGizmo » 01 Okt 2019, 20:04

Your code will only work on little endians.
Arduino für fischertechnik: ftDuino http://ftduino.de, ftDuino32 http://ftduino.de/32

vleeuwen
Beiträge: 1564
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: RoboPro .rpp float calculation

Beitrag von vleeuwen » 01 Okt 2019, 22:58

I know, but the organisation in the byte array can be adapted to the actual situation.
However for .NET framework and the RoboPro serialization this gives the right result.
For the reader who are not familiair with the meaning of "endians", see for example:
https://en.wikipedia.org/wiki/Endianness

Endianness refers to the order of bytes (or sometimes bits) within a binary representation of a number in hardware as well in software.

Benutzeravatar
MasterOfGizmo
Beiträge: 2720
Registriert: 30 Nov 2014, 07:44

Re: RoboPro .rpp float calculation

Beitrag von MasterOfGizmo » 02 Okt 2019, 09:43

As I showed above it's easy to convert directly without mapping the data to byte arrays first. This would make the code much simpler and it would run on any target without modifications.

Something like:

Code: Alles auswählen

double mantissa = (((uint32_t)((uint16_t)value1)<<16) + ((uint16_t)value2)) / pow(2,32);
if(value0 < 0) mantissa = -mantissa;
int exponent = (value0 & 0x7fff)-8192;
double result = mantissa * pow(2,exponent);
Arduino für fischertechnik: ftDuino http://ftduino.de, ftDuino32 http://ftduino.de/32

Benutzeravatar
MasterOfGizmo
Beiträge: 2720
Registriert: 30 Nov 2014, 07:44

Re: RoboPro .rpp float calculation

Beitrag von MasterOfGizmo » 02 Okt 2019, 10:02

or if your prefer a simple one liner:

Code: Alles auswählen

double result = ((value0<0)?-1.0:1.0)*(((uint32_t)((uint16_t)value1)<<16) + ((uint16_t)value2)) / pow(2,8224-(value0 & 0x7fff));
Arduino für fischertechnik: ftDuino http://ftduino.de, ftDuino32 http://ftduino.de/32

vleeuwen
Beiträge: 1564
Registriert: 31 Okt 2010, 22:23
Wohnort: Enschede (NL)
Kontaktdaten:

Re: RoboPro .rpp float calculation

Beitrag von vleeuwen » 02 Okt 2019, 14:06

Certainly there are a lots of possibilities, no doubt about that.

I choose for this solution because it shows all the steps in C# and it has been based on this example: http://www.shikadi.net/moddingwiki/Turbo_Pascal_Real
One-liner code, the program language APL is famous for that, is less easy to understand and to modify later.
The compiler will do the optimization of the code.
The functional specification is the more important part

Code: Alles auswählen

        /// <summary>
        /// Converts a RoboPro  dataType 11, as use in the .rpp serialization file, into a Double 
        /// </summary>
        /// <param name="val0">string with a 2 bytes number, serialized as a signed integer </param>
        /// <param name="val1">string with a 2 bytes number, serialized as a signed integer</param>
        /// <param name="val2">string with a 2 bytes number, serialized as a signed integer</param>
        /// <returns> The value</returns>
        public static Double Convert(string val0, string val1, string val2)

Gesperrt