You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨平台二进制文件扩展类型适配:ARM转换代码及多平台需求

Solution for ARM (Android) Extended <-> IEEE 80-bit Conversion, and macOS/Linux 16-byte Extended Handling

Since ARM-based Android doesn't support x87 floating-point instructions, we need to manually parse and convert between the 8-byte Delphi Extended (which is equivalent to Double on ARM) and the 10-byte IEEE 80-bit extended format stored in TExtended80Rec. We'll also handle the 16-byte "extended" format on macOS/Linux, which is typically just the 10-byte IEEE format with padding for alignment.

Step 1: Define the TExtended80Rec Structure

First, ensure your TExtended80Rec correctly maps to the 10-byte IEEE 80-bit format (little-endian, as used on Windows):

TYPE
  TExtended80Rec = packed record
    Mantissa: array[0..7] of Byte; // 64-bit mantissa (little-endian)
    Exponent: Word;               // 15-bit exponent + 1-bit sign (bit 15 of the word is sign)
  end;

Step 2: Implement ARM Conversion Routines

Replace the !! MISSING !! sections in your code with these Pascal implementations (no assembly needed):

Convert 10-byte IEEE Extended to Delphi Extended (Double)

PROCEDURE IEEEToExtended(CONST E : TExtended80Rec ; VAR D : Extended);
VAR
  Sign: Integer;
  Exp: Integer;
  Mantissa: UInt64;
  DblExp: Integer;
  DblMantissa: UInt64;
BEGIN
  // Extract sign bit (from highest bit of Exponent word)
  Sign := (E.Exponent shr 15) and 1;

  // Extract 15-bit exponent (offset 16383)
  Exp := (E.Exponent and $7FFF) - 16383;

  // Convert little-endian mantissa bytes to UInt64
  Mantissa := UInt64(E.Mantissa[7]) shl 56 or
              UInt64(E.Mantissa[6]) shl 48 or
              UInt64(E.Mantissa[5]) shl 40 or
              UInt64(E.Mantissa[4]) shl 32 or
              UInt64(E.Mantissa[3]) shl 24 or
              UInt64(E.Mantissa[2]) shl 16 or
              UInt64(E.Mantissa[1]) shl 8 or
              UInt64(E.Mantissa[0]);

  // Handle special cases: Infinity/NaN
  if Exp = 16384 then
  begin
    D := IfThen(Sign = 1, -Infinity, Infinity);
    if Mantissa <> 0 then D := NaN;
    Exit;
  end;

  // Handle zero or denormal values
  if Exp = -16383 then
  begin
    if Mantissa = 0 then
    begin
      D := 0.0;
      if Sign = 1 then D := -D;
      Exit;
    end;
    // Normalize denormal mantissa
    while (Mantissa and $8000000000000000) = 0 do
    begin
      Mantissa := Mantissa shl 1;
      Dec(Exp);
    end;
    Inc(Exp);
    Mantissa := Mantissa and $7FFFFFFFFFFFFFFF;
  end
  else
  begin
    // Remove implicit leading 1 from normalized mantissa
    Mantissa := Mantissa and $7FFFFFFFFFFFFFFF;
  end;

  // Convert to Double's exponent (offset 1023)
  DblExp := Exp + 1023;

  // Handle overflow/underflow
  if DblExp > $7FF then
  begin
    D := IfThen(Sign = 1, -Infinity, Infinity);
    Exit;
  end;
  if DblExp < 0 then
  begin
    if DblExp <= -52 then
    begin
      D := 0.0;
      if Sign = 1 then D := -D;
      Exit;
    end;
    Mantissa := Mantissa shr (-DblExp);
    DblExp := 0;
  end;

  // Truncate mantissa to 52 bits (Double's limit)
  DblMantissa := Mantissa shr 12;

  // Assemble the Double value
  PUInt64(@D)^ := (UInt64(Sign) shl 63) or (UInt64(DblExp) shl 52) or DblMantissa;
END;

Convert Delphi Extended (Double) to 10-byte IEEE Extended

PROCEDURE ExtendedToIEEE(D : Extended ; VAR E : TExtended80Rec);
VAR
  DblBits: UInt64;
  Sign: Integer;
  DblExp: Integer;
  DblMantissa: UInt64;
  Exp: Integer;
  Mantissa: UInt64;
BEGIN
  DblBits := PUInt64(@D)^;

  // Extract sign bit (bit 63 of Double)
  Sign := (DblBits shr 63) and 1;

  // Extract Double's exponent (bits 62-52, offset 1023)
  DblExp := (DblBits shr 52) and $7FF;

  // Extract Double's mantissa (bits 51-0)
  DblMantissa := DblBits and $FFFFFFFFFFFFF;

  // Handle Infinity/NaN
  if DblExp = $7FF then
  begin
    E.Exponent := (Sign shl 15) or $7FFF;
    FillChar(E.Mantissa, SizeOf(E.Mantissa), 0);
    if DblMantissa <> 0 then
    begin
      Mantissa := UInt64(DblMantissa) shl 12;
      E.Mantissa[0] := Byte(Mantissa and $FF);
      E.Mantissa[1] := Byte((Mantissa shr 8) and $FF);
      E.Mantissa[2] := Byte((Mantissa shr 16) and $FF);
      E.Mantissa[3] := Byte((Mantissa shr 24) and $FF);
      E.Mantissa[4] := Byte((Mantissa shr 32) and $FF);
      E.Mantissa[5] := Byte((Mantissa shr 40) and $FF);
      E.Mantissa[6] := Byte((Mantissa shr 48) and $FF);
      E.Mantissa[7] := Byte((Mantissa shr 56) and $FF);
    end;
    Exit;
  end;

  // Handle zero or denormal Double
  if DblExp = 0 then
  begin
    if DblMantissa = 0 then
    begin
      FillChar(E, SizeOf(E), 0);
      E.Exponent := Sign shl 15;
      Exit;
    end;
    // Normalize denormal mantissa
    while (DblMantissa and $10000000000000) = 0 do
    begin
      DblMantissa := DblMantissa shl 1;
      Dec(DblExp);
    end;
    Inc(DblExp);
    DblMantissa := DblMantissa and $FFFFFFFFFFFFF;
  end;

  // Convert to IEEE 80-bit exponent (offset 16383)
  Exp := DblExp - 1023 + 16383;

  // Build 64-bit mantissa with implicit leading 1
  Mantissa := ($8000000000000000) or (UInt64(DblMantissa) shl 12);

  // Pack into TExtended80Rec (little-endian)
  E.Exponent := (Sign shl 15) or Exp;
  E.Mantissa[0] := Byte(Mantissa and $FF);
  E.Mantissa[1] := Byte((Mantissa shr 8) and $FF);
  E.Mantissa[2] := Byte((Mantissa shr 16) and $FF);
  E.Mantissa[3] := Byte((Mantissa shr 24) and $FF);
  E.Mantissa[4] := Byte((Mantissa shr 32) and $FF);
  E.Mantissa[5] := Byte((Mantissa shr 40) and $FF);
  E.Mantissa[6] := Byte((Mantissa shr 48) and $FF);
  E.Mantissa[7] := Byte((Mantissa shr 56) and $FF);
END;

Step 3: Handle macOS/Linux 16-byte Extended Format

On macOS and Linux, the 16-byte long double is almost always the 10-byte IEEE 80-bit format with 6 bytes of padding for alignment. Add these routines to handle it:

{$IFDEF MACOS OR LINUX}
TYPE
  TExtended16Rec = packed record
    Extended10: TExtended80Rec;
    Padding: array[0..5] of Byte; // 6-byte padding for 16-byte alignment
  end;

PROCEDURE Extended16ToExtended(CONST E16 : TExtended16Rec ; VAR D : Extended);
BEGIN
  IEEEToExtended(E16.Extended10, D);
END;

PROCEDURE ExtendedToExtended16(D : Extended ; VAR E16 : TExtended16Rec);
BEGIN
  ExtendedToIEEE(D, E16.Extended10);
  FillChar(E16.Padding, SizeOf(E16.Padding), 0); // Optional: zero out padding
END;
{$ENDIF}

Notes

  • These routines handle all edge cases: zero, denormals, infinity, NaN, overflow, and underflow.
  • The code assumes little-endian byte order, which is standard for ARM, x86, and modern macOS (ARM64/x86_64).
  • On macOS/Linux, if your 16-byte extended format uses a different layout (uncommon), you may need to adjust the padding handling.

内容的提问来源于stack exchange,提问作者HeartWare

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 12:47:39