| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- using System;
- namespace ChocolArm64.Instruction
- {
- static class ASoftFloat
- {
- static ASoftFloat()
- {
- InvSqrtEstimateTable = BuildInvSqrtEstimateTable();
- }
- private static readonly byte[] InvSqrtEstimateTable;
- private static byte[] BuildInvSqrtEstimateTable()
- {
- byte[] Table = new byte[512];
- for (ulong index = 128; index < 512; index++)
- {
- ulong a = index;
- if (a < 256)
- {
- a = (a << 1) + 1;
- }
- else
- {
- a = (a | 1) << 1;
- }
- ulong b = 256;
- while (a * (b + 1) * (b + 1) < (1ul << 28))
- {
- b++;
- }
- b = (b + 1) >> 1;
- Table[index] = (byte)(b & 0xFF);
- }
- return Table;
- }
- public static float InvSqrtEstimate(float x)
- {
- return (float)InvSqrtEstimate((double)x);
- }
- public static double InvSqrtEstimate(double x)
- {
- ulong x_bits = (ulong)BitConverter.DoubleToInt64Bits(x);
- ulong x_sign = x_bits & 0x8000000000000000;
- long x_exp = (long)((x_bits >> 52) & 0x7FF);
- ulong scaled = x_bits & ((1ul << 52) - 1);
- if (x_exp == 0x7ff)
- {
- if (scaled == 0)
- {
- // Infinity -> Zero
- return BitConverter.Int64BitsToDouble((long)x_sign);
- }
- // NaN
- return BitConverter.Int64BitsToDouble((long)(x_bits | 0x0008000000000000));
- }
- if (x_exp == 0)
- {
- if (scaled == 0)
- {
- // Zero -> Infinity
- return BitConverter.Int64BitsToDouble((long)(x_sign | 0x7ff0000000000000));
- }
- // Denormal
- while ((scaled & (1 << 51)) == 0)
- {
- scaled <<= 1;
- x_exp--;
- }
- scaled <<= 1;
- }
- if (((ulong)x_exp & 1) == 1)
- {
- scaled >>= 45;
- scaled &= 0xFF;
- scaled |= 0x80;
- }
- else
- {
- scaled >>= 44;
- scaled &= 0xFF;
- scaled |= 0x100;
- }
- ulong result_exp = ((ulong)(3068 - x_exp) / 2) & 0x7FF;
- ulong estimate = (ulong)InvSqrtEstimateTable[scaled];
- ulong fraction = estimate << 44;
- ulong result = x_sign | (result_exp << 52) | fraction;
- return BitConverter.Int64BitsToDouble((long)result);
- }
- }
- }
|