Turbo Pascal Real

From ModdingWiki
Jump to navigation Jump to search

While most languages use a 32-bit or 64-bit floating point decimal variable, usually called single or double, Turbo Pascal featured an uncommon 48-bit float called a real which served the same function as a float. Real variable types were frequently used in the early versions of Pascal because it did not have native support for 32-bit integers until later versions, so, if you wanted to store a number greater than 32,767 or a number with a decimal value, you had to use a real. 32 and 64-bit floats were introduced in Turbo Pascal version 5. Pascal's successor, Delphi, did not feature reals as a variable type.

A Pascal real has a value range of 2.9 x 10-39 to 1.7 x 1038.

The structure of a Pascal real is seen in the diagram below.

Byte 0 1 2 3 4 5
Bit 01234567 01234567 01234567 01234567 01234567 01234567
Value EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM SMMMMMMM

Where E is Exponent, M is Mantissa, and S is the Sign bit.

Conversion

Any games written in Turbo Pascal may feature game data files with reals encoded into them. However, unless your mod program is written in Turbo Pascal, you won't have any way to directly read or write these values. The simplest way to do this is to convert each real into a double when reading them from a file, and from a double into a real when writing them back to a file.

Real to Double

This will take a real as input and give a double as output.

C#

// This program expects a byte array named real48[6] to be loaded with the 6 bytes of the real from the file.

Double exponentbase = 129d;
Double exponent = real48[0] - exponentbase; // The exponent is offset so deduct the base.

// Now Calculate the mantissa
Double mantissa = 0.0;
Double value = 1.0;
// For Each Byte.
for (int i = 5; i >= 1; i--)
{
    int startbit = 7;
    if (i == 5)
    { startbit = 6; } //skip the sign bit.

    //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) //if this bit is set.
        {
            mantissa += value; // add the value.
        }

    }
}

if (mantissa == 1.0 && real48[0] == 0) // Test for null value
    return 0.0;

double factor = ((real48[5] & 0x80) != 0) ? -1 : 1; // Change sign if bit 7 is set

return factor * (1 + mantissa) * Math.Pow(2.0, exponent);

FreeBASIC

' Load the real from a file into a byte array.
Open "Real.bin" For Binary As #1
Dim Real48(0 To 5) As UByte
Dim ByteNo As Byte
For ByteNo = 0 To 5
    Get #1, , Real48(ByteNo)
Next ByteNo
Close #1

' Get the exponent value, and eliminate the 129 offset.
Dim Exponent As Double
Exponent = Real48(0) - 129.0

' Calculate the mantissa.
Dim Mantissa As Double
Dim Value As Double
Value = 1
For ByteNo = 5 To 1 Step -1
    Dim StartBit As Byte
    StartBit = 7
    If ByteNo = 5 Then StartBit = 6     ' Skip the sign bit.
    
    Dim BitNo As Byte
    For BitNo = StartBit To 0 Step -1
        Value = Value / 2
        If ((Real48(ByteNo) Shr BitNo) And 1) = 1 Then
            Mantissa = Mantissa + Value
        End If
    Next BitNo
Next ByteNo
' Add the implicit 1.
Mantissa = Mantissa + 1

' Test for a null value.
Dim Result As Double
If Mantissa = 1.0 And Real48(0) = 0 Then
    Result = 0.0
Else
    ' If the sign bit is set, make the value negative.
    If Real48(5) AND &H80 = -1 Then
        Mantissa = -Mantissa
    End If
    
    ' Raise the mantissa to the specified exponent.
    Result = Mantissa * (2 ^ Exponent)
End If

Print Result
Sleep

Double to Real

This will take a double as input and give a real as output.