Files
tdkpin/original/reconstructed/tdkpin_real48.c
T
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
Replace the partial mechanics transcriptions with a separate, readable C11
reconstruction of the complete Win16 image while preserving the original raw
Ghidra export as immutable evidence. Cover all ordinary and overlapping entry
points, Borland runtime behavior, Win16 imports, segmented data, callbacks,
resources, indirect control flow, physics, rendering, persistence, and
startup/shutdown lifecycles.

Add deterministic extraction and audit tooling plus address-linked ledgers for
functions, imports, DGROUP ranges and objects, relocations, resources, and
callbacks. The final gate records zero raw, partial, restored, unknown,
blocked, or unclassified required units. Keep the semantic-fidelity boundary
explicit: the portable C is not claimed to reproduce a byte-identical Borland
NE build.

Add strict focused harnesses for every reconstructed C unit, exact resource
round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source
or Cargo metadata is changed in this phase.

Test Plan:
- `bash original/tools/test_reconstructed_c.sh` -- passed
- `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit
- `python3 original/tools/audit_reconstruction.py --require-complete` -- passed
- `git diff --cached --check` -- passed
- `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
2026-08-23 16:41:17 +02:00

894 lines
30 KiB
C

/* Bit-exact core conversions and comparisons for Borland's software Real48. */
#include "tdkpin_real48.h"
#include "tdkpin_borland_runtime.h"
#include <limits.h>
enum {
REAL48_EXPONENT_BIAS = 129,
REAL48_EXPLICIT_FRACTION_BITS = 39,
REAL48_SIGN = 0x80,
BORLAND_RUNTIME_ERROR_DIVIDE_BY_ZERO = 200,
BORLAND_RUNTIME_ERROR_FLOAT_OVERFLOW = 205,
BORLAND_RUNTIME_ERROR_INVALID_FLOAT = 207,
};
/* Code5 1020:1418..1435 — ArcTan odd-series coefficients, highest first. */
static const BorlandReal48 g_arctan_coefficients[5] = {
{{0x7d, 0xe8, 0xa2, 0x8b, 0x2e, 0xba}}, /* -1/11 */
{{0x7d, 0x8e, 0xe3, 0x38, 0x8e, 0x63}}, /* +1/9 */
{{0x7e, 0x49, 0x92, 0x24, 0x49, 0x92}}, /* -1/7 */
{{0x7e, 0xcd, 0xcc, 0xcc, 0xcc, 0x4c}}, /* +1/5 */
{{0x7f, 0xab, 0xaa, 0xaa, 0xaa, 0xaa}}, /* -1/3 */
};
/* Code5 1020:13e8..1417 — ArcTan reduction thresholds and tan/angle pairs. */
static const BorlandReal48 g_arctan_direct_limit =
{{0x7e, 0x4a, 0x8e, 0xe9, 0x6f, 0x0c}};
static const BorlandReal48 g_arctan_tan_pi_over_8 =
{{0x7f, 0xe7, 0xcf, 0xcc, 0x13, 0x54}};
static const BorlandReal48 g_arctan_tan_pi_over_12 =
{{0x7f, 0xf6, 0xf4, 0xa2, 0x30, 0x09}};
static const BorlandReal48 g_pi_over_12 =
{{0x7f, 0x6a, 0xc1, 0x91, 0x0a, 0x06}};
static const BorlandReal48 g_arctan_second_threshold =
{{0x80, 0xb5, 0x9e, 0x8a, 0x6f, 0x44}};
static const BorlandReal48 g_arctan_tan_pi_over_6 =
{{0x80, 0x82, 0x2c, 0x3a, 0xcd, 0x13}};
static const BorlandReal48 g_pi_over_6 =
{{0x80, 0x6a, 0xc1, 0x91, 0x0a, 0x06}};
static const BorlandReal48 g_real48_one =
{{0x81, 0, 0, 0, 0, 0}};
static const BorlandReal48 g_pi_over_4 =
{{0x80, 0x21, 0xa2, 0xda, 0x0f, 0x49}};
static const BorlandReal48 g_pi_over_2 =
{{0x81, 0x21, 0xa2, 0xda, 0x0f, 0x49}};
/* Code5 1020:1240..1263 and constants used by Ln at 11bb. */
static const BorlandReal48 g_ln_coefficients[6] = {
{{0x7d, 0x8a, 0x9d, 0xd8, 0x89, 0x1d}}, /* 1/13 */
{{0x7d, 0xe9, 0xa2, 0x8b, 0x2e, 0x3a}}, /* 1/11 */
{{0x7d, 0x8e, 0xe3, 0x38, 0x8e, 0x63}}, /* 1/9 */
{{0x7e, 0x49, 0x92, 0x24, 0x49, 0x12}}, /* 1/7 */
{{0x7e, 0xcd, 0xcc, 0xcc, 0xcc, 0x4c}}, /* 1/5 */
{{0x7f, 0xab, 0xaa, 0xaa, 0xaa, 0x2a}}, /* 1/3 */
};
static const BorlandReal48 g_sqrt_one_half =
{{0x80, 0xfb, 0x33, 0xf3, 0x04, 0x35}};
static const BorlandReal48 g_half_ln_two =
{{0x7f, 0xd2, 0xf7, 0x17, 0x72, 0x31}};
static const BorlandReal48 g_ln_two =
{{0x80, 0xd2, 0xf7, 0x17, 0x72, 0x31}};
/* Code5 1020:12d7..1306 — Exp polynomial, highest coefficient first. */
static const BorlandReal48 g_exp_coefficients[8] = {
{{0x6d, 0x2e, 0x1d, 0x11, 0x60, 0x31}},
{{0x70, 0x46, 0x2c, 0xfe, 0xe5, 0x7f}},
{{0x74, 0x36, 0x7c, 0x89, 0x84, 0x21}},
{{0x77, 0x53, 0x3c, 0xff, 0xc3, 0x2e}},
{{0x7a, 0xd2, 0x7d, 0x5b, 0x95, 0x1d}},
{{0x7c, 0x25, 0xb8, 0x46, 0x58, 0x63}},
{{0x7e, 0x16, 0xfc, 0xef, 0xfd, 0x75}},
{{0x80, 0xd2, 0xf7, 0x17, 0x72, 0x31}},
};
static const BorlandReal48 g_sqrt_two =
{{0x81, 0xfb, 0x33, 0xf3, 0x04, 0x35}};
/* Code5 1020:1191..11ba — Sin odd-series coefficients, highest first. */
static const BorlandReal48 g_sin_coefficients[7] = {
{{0x58, 0x9d, 0x39, 0x9f, 0x3f, 0xd7}}, /* -1/15! */
{{0x60, 0x43, 0x9d, 0x30, 0x92, 0x30}}, /* +1/13! */
{{0x67, 0xaa, 0x3f, 0x28, 0x32, 0xd7}}, /* -1/11! */
{{0x6e, 0xb6, 0x2a, 0x1d, 0xef, 0x38}}, /* +1/9! */
{{0x74, 0x0d, 0xd0, 0x00, 0x0d, 0xd0}}, /* -1/7! */
{{0x7a, 0x88, 0x88, 0x88, 0x88, 0x08}}, /* +1/5! */
{{0x7e, 0xab, 0xaa, 0xaa, 0xaa, 0xaa}}, /* -1/3! */
};
static const BorlandReal48 g_two_pi =
{{0x83, 0x21, 0xa2, 0xda, 0x0f, 0x49}};
static uint8_t real48_exponent(BorlandReal48 value)
{
return value.bytes[0];
}
static bool real48_negative(BorlandReal48 value)
{
return (value.bytes[5] & REAL48_SIGN) != 0;
}
static uint64_t real48_fraction(BorlandReal48 value)
{
return (uint64_t)value.bytes[1] |
((uint64_t)value.bytes[2] << 8) |
((uint64_t)value.bytes[3] << 16) |
((uint64_t)value.bytes[4] << 24) |
((uint64_t)(value.bytes[5] & 0x7f) << 32);
}
static uint64_t real48_significand(BorlandReal48 value)
{
return (UINT64_C(1) << REAL48_EXPLICIT_FRACTION_BITS) |
real48_fraction(value);
}
static BorlandReal48 make_real48(
uint8_t exponent, bool negative, uint64_t fraction)
{
BorlandReal48 result = {{0, 0, 0, 0, 0, 0}};
result.bytes[0] = exponent;
result.bytes[1] = (uint8_t)fraction;
result.bytes[2] = (uint8_t)(fraction >> 8);
result.bytes[3] = (uint8_t)(fraction >> 16);
result.bytes[4] = (uint8_t)(fraction >> 24);
result.bytes[5] =
(uint8_t)((fraction >> 32) | (negative ? REAL48_SIGN : 0));
return result;
}
static BorlandReal48Result real48_pack_internal(
uint64_t internal, int16_t exponent, bool negative)
{
internal += UINT64_C(0x80);
if ((internal & (UINT64_C(1) << 48)) != 0) {
internal >>= 1;
exponent++;
}
if (exponent <= 0) {
return (BorlandReal48Result){
borland_real48_zero_registers(), false, false};
}
if (exponent > UINT8_MAX) {
return (BorlandReal48Result){
borland_real48_zero_registers(), true, false};
}
uint64_t significand = internal >> 8;
uint64_t fraction = significand -
(UINT64_C(1) << REAL48_EXPLICIT_FRACTION_BITS);
return (BorlandReal48Result){
make_real48((uint8_t)exponent, negative, fraction), false, false};
}
static BorlandReal48Result real48_add_with_signs(
BorlandReal48 left, BorlandReal48 right, bool right_negative)
{
uint8_t left_exponent = real48_exponent(left);
uint8_t right_exponent = real48_exponent(right);
if (right_exponent == 0) {
return (BorlandReal48Result){left, false, false};
}
if (left_exponent == 0) {
right.bytes[5] = (uint8_t)(
(right.bytes[5] & 0x7f) |
(right_negative ? REAL48_SIGN : 0));
return (BorlandReal48Result){right, false, false};
}
BorlandReal48 high = left;
BorlandReal48 low = right;
bool high_negative = real48_negative(left);
bool low_negative = right_negative;
if (right_exponent > left_exponent) {
high = right;
low = left;
uint8_t temporary_exponent = left_exponent;
left_exponent = right_exponent;
right_exponent = temporary_exponent;
high_negative = right_negative;
low_negative = real48_negative(left);
}
uint8_t difference = (uint8_t)(left_exponent - right_exponent);
if (difference >= 41) {
high.bytes[5] = (uint8_t)(
(high.bytes[5] & 0x7f) |
(high_negative ? REAL48_SIGN : 0));
return (BorlandReal48Result){high, false, false};
}
uint64_t high_internal = real48_significand(high) << 8;
uint64_t low_internal =
(real48_significand(low) << 8) >> difference;
uint64_t magnitude;
bool result_negative;
int16_t result_exponent = left_exponent;
if (high_negative == low_negative) {
magnitude = high_internal + low_internal;
result_negative = high_negative;
if ((magnitude & (UINT64_C(1) << 48)) != 0) {
magnitude >>= 1;
result_exponent++;
if (result_exponent > UINT8_MAX) {
return (BorlandReal48Result){
borland_real48_zero_registers(), true, false};
}
}
} else {
if (high_internal == low_internal) {
return (BorlandReal48Result){
borland_real48_zero_registers(), false, false};
}
if (high_internal > low_internal) {
magnitude = high_internal - low_internal;
result_negative = high_negative;
} else {
magnitude = low_internal - high_internal;
result_negative = low_negative;
}
while ((magnitude & (UINT64_C(1) << 47)) == 0) {
magnitude <<= 1;
result_exponent--;
if (result_exponent == 0) {
return (BorlandReal48Result){
borland_real48_zero_registers(), false, false};
}
}
}
return real48_pack_internal(
magnitude, result_exponent, result_negative);
}
/* 1020:0cd4 — register-form software Real48 addition. */
BorlandReal48Result borland_real48_add_registers(
BorlandReal48 left, BorlandReal48 right)
{
return real48_add_with_signs(left, right, real48_negative(right));
}
/* 1020:0cd0 — toggle DI's sign bit, then enter the shared addition body. */
BorlandReal48Result borland_real48_subtract_registers(
BorlandReal48 left, BorlandReal48 right)
{
return real48_add_with_signs(left, right, !real48_negative(right));
}
typedef struct {
uint64_t low;
uint16_t high;
} Real48Product80;
static Real48Product80 multiply_40_by_40(uint64_t left, uint64_t right)
{
uint64_t low_product =
(uint64_t)(uint32_t)left * (uint32_t)right;
uint64_t cross =
(left >> 32) * (uint32_t)right +
(right >> 32) * (uint32_t)left;
uint64_t low = low_product + (cross << 32);
uint32_t high = (uint32_t)(
(left >> 32) * (right >> 32) +
(cross >> 32) +
(low < low_product));
return (Real48Product80){low, (uint16_t)high};
}
/* 1020:0d97 — exact 40x40 product followed by Borland's eight guard bits. */
BorlandReal48Result borland_real48_multiply_registers(
BorlandReal48 left, BorlandReal48 right)
{
if (real48_exponent(left) == 0 || real48_exponent(right) == 0) {
return (BorlandReal48Result){
borland_real48_zero_registers(), false, false};
}
Real48Product80 product = multiply_40_by_40(
real48_significand(left), real48_significand(right));
bool top_bit_79 = (product.high & 0x8000) != 0;
uint8_t shift = top_bit_79 ? 32 : 31;
uint64_t internal =
(product.low >> shift) |
((uint64_t)product.high << (64 - shift));
int16_t exponent =
(int16_t)real48_exponent(left) + real48_exponent(right) -
(top_bit_79 ? 128 : 129);
return real48_pack_internal(
internal,
exponent,
real48_negative(left) != real48_negative(right));
}
/* 1020:0e93 — shared underflow/zero result: AX=BX=DX=0. */
BorlandReal48 borland_real48_zero_registers(void)
{
return (BorlandReal48){{0, 0, 0, 0, 0, 0}};
}
/* 1020:0e9a — restoring division generating 40 result plus eight guard bits. */
BorlandReal48Result borland_real48_divide_registers(
BorlandReal48 left, BorlandReal48 right)
{
if (real48_exponent(right) == 0) {
return (BorlandReal48Result){
borland_real48_zero_registers(), false, true};
}
if (real48_exponent(left) == 0) {
return (BorlandReal48Result){
borland_real48_zero_registers(), false, false};
}
uint64_t numerator = real48_significand(left);
uint64_t denominator = real48_significand(right);
int16_t exponent =
(int16_t)real48_exponent(left) - real48_exponent(right) + 129;
if (numerator < denominator) {
numerator <<= 1;
exponent--;
}
uint64_t internal = 0;
uint64_t remainder = numerator;
for (uint8_t bit = 0; bit < 48; bit++) {
bool quotient_bit = remainder >= denominator;
if (quotient_bit) {
remainder -= denominator;
}
internal = (internal << 1) | quotient_bit;
remainder <<= 1;
}
return real48_pack_internal(
internal,
exponent,
real48_negative(left) != real48_negative(right));
}
/*
* 1020:1031/103b/1045/104f — near arithmetic entries that save and restore
* CX:SI:DI around the corresponding core. C by-value operands express that
* register-preservation contract directly.
*/
BorlandReal48Result borland_real48_add_preserving_right(
BorlandReal48 left, BorlandReal48 right)
{
return borland_real48_add_registers(left, right);
}
BorlandReal48Result borland_real48_subtract_preserving_right(
BorlandReal48 left, BorlandReal48 right)
{
return borland_real48_subtract_registers(left, right);
}
BorlandReal48Result borland_real48_multiply_preserving_right(
BorlandReal48 left, BorlandReal48 right)
{
return borland_real48_multiply_registers(left, right);
}
BorlandReal48Result borland_real48_divide_preserving_right(
BorlandReal48 left, BorlandReal48 right)
{
return borland_real48_divide_registers(left, right);
}
/* 1020:1059 — Pascal Int: clear fractional significand bits toward zero. */
BorlandReal48 borland_real48_integer_part(BorlandReal48 value)
{
uint8_t exponent = real48_exponent(value);
if (exponent >= 168) {
return value;
}
if (exponent <= 128) {
return borland_real48_zero_registers();
}
uint8_t fractional_bits = (uint8_t)(168 - exponent);
uint64_t significand = real48_significand(value);
uint64_t mask = ~((UINT64_C(1) << fractional_bits) - 1);
uint64_t integer_significand = significand & mask;
uint64_t fraction = integer_significand -
(UINT64_C(1) << REAL48_EXPLICIT_FRACTION_BITS);
return make_real48(exponent, real48_negative(value), fraction);
}
/* 1020:10aa — Pascal Frac: original minus Int(original). */
BorlandReal48 borland_real48_fractional_part(BorlandReal48 value)
{
return borland_real48_subtract_registers(
value, borland_real48_integer_part(value))
.value;
}
/*
* 1020:10be — Borland Sqrt Newton iteration. The initial exponent transform,
* retained input mantissa, divide/add/exponent-decrement step, and convergence
* test on the exponent of new-old follow the register routine exactly.
*/
BorlandReal48 borland_real48_sqrt(BorlandReal48 value)
{
if (real48_exponent(value) == 0) {
return value;
}
if (real48_negative(value)) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_INVALID_FLOAT);
}
BorlandReal48 guess = value;
int8_t halved = (int8_t)(uint8_t)(real48_exponent(value) + 0x80);
halved >>= 1;
guess.bytes[0] = (uint8_t)((uint8_t)halved + 0x80);
uint8_t convergence_exponent = (uint8_t)(guess.bytes[0] - 0x14);
while (true) {
BorlandReal48 quotient =
borland_real48_divide_preserving_right(value, guess).value;
BorlandReal48 next =
borland_real48_add_preserving_right(quotient, guess).value;
next.bytes[0]--;
BorlandReal48 difference =
borland_real48_subtract_registers(next, guess).value;
guess = next;
if (difference.bytes[0] < convergence_exponent) {
return guess;
}
}
}
/*
* 1020:1455 — Horner evaluator used by the transcendental routines:
* result = 1 + x*(c[n-1] + x*(... + x*c[0])). The target multiplies once
* before advancing to each later coefficient, so table order is significant.
*/
BorlandReal48 borland_real48_polynomial_plus_one(
BorlandReal48 argument,
const BorlandReal48 *coefficients,
uint16_t count)
{
BorlandReal48 result = coefficients[0];
for (uint16_t index = 0; index < count; index++) {
if (index != 0) {
result = borland_real48_add_registers(
result, coefficients[index])
.value;
}
result = borland_real48_multiply_registers(result, argument).value;
}
return borland_real48_add_registers(
result, make_real48(0x81, false, 0))
.value;
}
/* 1020:143c — x * polynomial_plus_one(x*x, table, count). */
BorlandReal48 borland_real48_odd_polynomial(
BorlandReal48 argument,
const BorlandReal48 *coefficients,
uint16_t count)
{
BorlandReal48 squared =
borland_real48_multiply_registers(argument, argument).value;
BorlandReal48 polynomial = borland_real48_polynomial_plus_one(
squared, coefficients, count);
return borland_real48_multiply_registers(polynomial, argument).value;
}
/* 1020:1436 — fixed-table ArcTan series entry sharing the 143c tail. */
BorlandReal48 borland_real48_arctan_series(BorlandReal48 argument)
{
return borland_real48_odd_polynomial(
argument,
g_arctan_coefficients,
(uint16_t)(sizeof(g_arctan_coefficients) /
sizeof(g_arctan_coefficients[0])));
}
/*
* 1020:1307 — ArcTan with Borland's fixed argument reductions. Values above
* one are inverted; three tan-addition ranges reduce to the direct odd series;
* then the reciprocal and original-sign transforms are applied in that order.
*/
BorlandReal48 borland_real48_arctan(BorlandReal48 argument)
{
if (real48_exponent(argument) == 0) {
return argument;
}
bool negative = real48_negative(argument);
argument.bytes[5] &= 0x7f;
bool reciprocal =
borland_real48_compare_registers(argument, g_real48_one) >= 0;
if (reciprocal) {
argument = borland_real48_divide_registers(
g_real48_one, argument)
.value;
}
BorlandReal48 result;
if (borland_real48_compare_registers(
argument, g_arctan_direct_limit) < 0) {
result = borland_real48_arctan_series(argument);
} else {
const BorlandReal48 *tangent;
const BorlandReal48 *angle;
if (borland_real48_compare_registers(
argument, g_arctan_tan_pi_over_8) < 0) {
tangent = &g_arctan_tan_pi_over_12;
angle = &g_pi_over_12;
} else if (borland_real48_compare_registers(
argument, g_arctan_second_threshold) < 0) {
tangent = &g_arctan_tan_pi_over_6;
angle = &g_pi_over_6;
} else {
tangent = &g_real48_one;
angle = &g_pi_over_4;
}
BorlandReal48 numerator =
borland_real48_subtract_preserving_right(
argument, *tangent)
.value;
BorlandReal48 denominator =
borland_real48_add_registers(
borland_real48_multiply_registers(argument, *tangent).value,
g_real48_one)
.value;
BorlandReal48 reduced =
borland_real48_divide_registers(numerator, denominator).value;
result = borland_real48_add_registers(
borland_real48_arctan_series(reduced), *angle)
.value;
}
if (reciprocal) {
result = borland_real48_subtract_registers(g_pi_over_2, result).value;
}
if (negative && real48_exponent(result) != 0) {
result.bytes[5] ^= REAL48_SIGN;
}
return result;
}
/*
* 1020:11bb — natural logarithm. Normalize the input exponent, center its
* mantissa with sqrt(1/2), evaluate the atanh odd series, double it, and add
* the signed exponent displacement times ln(2). Results below exponent 67 are
* flushed to canonical zero exactly like the final CMP/JAE sequence.
*/
BorlandReal48 borland_real48_ln(BorlandReal48 argument)
{
if (real48_exponent(argument) == 0 || real48_negative(argument)) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_INVALID_FLOAT);
}
int8_t exponent_displacement =
(int8_t)(uint8_t)(real48_exponent(argument) - 0x81);
argument.bytes[0] = 0x81;
BorlandReal48 centered =
borland_real48_multiply_registers(argument, g_sqrt_one_half).value;
BorlandReal48 numerator =
borland_real48_subtract_registers(centered, g_real48_one).value;
BorlandReal48 denominator =
borland_real48_add_registers(centered, g_real48_one).value;
BorlandReal48 ratio =
borland_real48_divide_registers(numerator, denominator).value;
BorlandReal48 mantissa_log = borland_real48_odd_polynomial(
ratio,
g_ln_coefficients,
(uint16_t)(sizeof(g_ln_coefficients) / sizeof(g_ln_coefficients[0])));
mantissa_log.bytes[0]++;
mantissa_log = borland_real48_add_registers(
mantissa_log, g_half_ln_two)
.value;
BorlandReal48 exponent_term = borland_real48_multiply_registers(
borland_i32_to_real48_registers(exponent_displacement), g_ln_two)
.value;
BorlandReal48 result =
borland_real48_add_registers(mantissa_log, exponent_term).value;
return real48_exponent(result) < 0x67
? borland_real48_zero_registers()
: result;
}
/*
* 1020:1264 — exponential. Reduce |x| by ln(2), round twice the quotient,
* evaluate the fixed 2^r polynomial, apply sqrt(2) for an odd reduction, and
* scale through the Real48 exponent byte. A negative original input takes the
* reciprocal only after the positive path is complete.
*/
BorlandReal48 borland_real48_exp(BorlandReal48 argument)
{
bool negative = real48_negative(argument);
argument.bytes[5] &= 0x7f;
BorlandReal48 quotient =
borland_real48_divide_registers(argument, g_ln_two).value;
if (real48_exponent(quotient) >= 0x88) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_FLOAT_OVERFLOW);
}
BorlandReal48 doubled_quotient = quotient;
doubled_quotient.bytes[0]++;
BorlandReal48IntegerResult rounded =
borland_real48_to_i32_registers(doubled_quotient, true);
if (rounded.overflow) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_FLOAT_OVERFLOW);
}
uint16_t reduction = (uint16_t)rounded.value;
BorlandReal48 half_reduction =
borland_i32_to_real48_registers(rounded.value);
if (real48_exponent(half_reduction) != 0) {
half_reduction.bytes[0]--;
}
BorlandReal48 reduced = borland_real48_subtract_registers(
quotient, half_reduction)
.value;
BorlandReal48 result = borland_real48_polynomial_plus_one(
reduced,
g_exp_coefficients,
(uint16_t)(sizeof(g_exp_coefficients) /
sizeof(g_exp_coefficients[0])));
if ((reduction & 1) != 0) {
result = borland_real48_multiply_registers(result, g_sqrt_two).value;
}
uint8_t exponent_increment = (uint8_t)(reduction >> 1);
uint16_t scaled_exponent =
(uint16_t)real48_exponent(result) + exponent_increment;
if (scaled_exponent > UINT8_MAX) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_FLOAT_OVERFLOW);
}
result.bytes[0] = (uint8_t)scaled_exponent;
if (negative) {
result = borland_real48_divide_registers(g_real48_one, result).value;
}
return result;
}
/*
* 1020:1130 — Sin shared entry inside the containing Cos routine. Reduce by
* 2*pi through Frac, fold [0,2*pi) through pi and pi/2, evaluate the odd
* series only above exponent 6c, then restore the half-cycle sign.
*/
BorlandReal48 borland_real48_sin(BorlandReal48 argument)
{
if (real48_exponent(argument) < 0x6c) {
return argument;
}
BorlandReal48 reduced = argument;
BorlandReal48 absolute = argument;
absolute.bytes[5] &= 0x7f;
if (borland_real48_compare_registers(absolute, g_two_pi) >= 0) {
BorlandReal48 quotient =
borland_real48_divide_preserving_right(argument, g_two_pi).value;
reduced = borland_real48_multiply_preserving_right(
borland_real48_fractional_part(quotient), g_two_pi)
.value;
}
if (real48_negative(reduced)) {
reduced = borland_real48_add_preserving_right(reduced, g_two_pi).value;
}
BorlandReal48 pi = g_two_pi;
pi.bytes[0]--;
bool positive_half_cycle =
borland_real48_compare_registers(reduced, pi) < 0;
if (!positive_half_cycle) {
reduced = borland_real48_subtract_preserving_right(reduced, pi).value;
}
BorlandReal48 half_pi = pi;
half_pi.bytes[0]--;
if (borland_real48_compare_registers(reduced, half_pi) >= 0) {
reduced.bytes[5] |= REAL48_SIGN;
reduced = borland_real48_add_registers(reduced, pi).value;
}
if (real48_exponent(reduced) >= 0x6c) {
reduced = borland_real48_odd_polynomial(
reduced,
g_sin_coefficients,
(uint16_t)(sizeof(g_sin_coefficients) /
sizeof(g_sin_coefficients[0])));
}
if (!positive_half_cycle && real48_exponent(reduced) != 0) {
reduced.bytes[5] ^= REAL48_SIGN;
}
return reduced;
}
/* 1020:111d — Cos prelude computes pi/2-x, then enters Sin at 1130. */
BorlandReal48 borland_real48_cos(BorlandReal48 argument)
{
BorlandReal48 minus_half_pi = g_pi_over_2;
minus_half_pi.bytes[5] |= REAL48_SIGN;
BorlandReal48 shifted =
borland_real48_add_registers(argument, minus_half_pi).value;
if (real48_exponent(shifted) != 0) {
shifted.bytes[5] ^= REAL48_SIGN;
}
return borland_real48_sin(shifted);
}
/*
* 1020:0f28 — unsigned Real48 magnitude ordering materialized from the flags.
* Equal zero exponents compare equal without inspecting the remaining bytes,
* exactly matching OR AL,AL followed by the early RET.
*/
int16_t borland_real48_compare_magnitude_registers(
BorlandReal48 left, BorlandReal48 right)
{
uint8_t left_exponent = real48_exponent(left);
uint8_t right_exponent = real48_exponent(right);
if (left_exponent != right_exponent) {
return left_exponent < right_exponent ? -1 : 1;
}
if (left_exponent == 0) {
return 0;
}
uint64_t left_fraction = real48_fraction(left);
uint64_t right_fraction = real48_fraction(right);
if (left_fraction == right_fraction) {
return 0;
}
return left_fraction < right_fraction ? -1 : 1;
}
/* 1020:0f11 — sign-aware comparison, reversing magnitude order if negative. */
int16_t borland_real48_compare_registers(
BorlandReal48 left, BorlandReal48 right)
{
bool left_negative = real48_negative(left);
bool right_negative = real48_negative(right);
if (left_negative != right_negative) {
return left_negative ? -1 : 1;
}
int16_t magnitude =
borland_real48_compare_magnitude_registers(left, right);
return left_negative ? (int16_t)-magnitude : magnitude;
}
/*
* 1020:0f3b — signed DX:AX integer to register-form Real48. Every int32_t is
* exact because Real48 carries forty significand bits.
*/
BorlandReal48 borland_i32_to_real48_registers(int32_t value)
{
if (value == 0) {
return borland_real48_zero_registers();
}
bool negative = value < 0;
uint32_t magnitude = negative
? (uint32_t)(0U - (uint32_t)value)
: (uint32_t)value;
uint8_t highest_bit = 0;
for (uint32_t scan = magnitude; scan > 1; scan >>= 1) {
highest_bit++;
}
uint64_t significand =
(uint64_t)magnitude <<
(REAL48_EXPLICIT_FRACTION_BITS - highest_bit);
uint64_t fraction = significand -
(UINT64_C(1) << REAL48_EXPLICIT_FRACTION_BITS);
return make_real48(
(uint8_t)(REAL48_EXPONENT_BIAS + highest_bit),
negative,
fraction);
}
/*
* 1020:0f77 — Real48 to signed DX:AX. `round` is the entry's CH byte: zero
* truncates, nonzero adds the first discarded bit before the signed-range
* check. Thus exact halves round away from zero, as Borland Round requires.
*/
BorlandReal48IntegerResult borland_real48_to_i32_registers(
BorlandReal48 value, bool round)
{
uint8_t exponent = real48_exponent(value);
if (exponent == 0) {
return (BorlandReal48IntegerResult){0, false};
}
int16_t highest_bit = (int16_t)exponent - REAL48_EXPONENT_BIAS;
if (highest_bit >= 32) {
return (BorlandReal48IntegerResult){0, true};
}
uint64_t significand = real48_significand(value);
int16_t shift = REAL48_EXPLICIT_FRACTION_BITS - highest_bit;
uint64_t magnitude = shift >= 64 ? 0 : significand >> shift;
if (round && shift > 0 && shift <= 40 &&
((significand >> (shift - 1)) & 1) != 0) {
magnitude++;
}
bool negative = real48_negative(value);
uint64_t limit = negative
? UINT64_C(0x80000000)
: (uint64_t)INT32_MAX;
bool overflow = magnitude > limit;
if (!negative) {
int32_t candidate = magnitude == UINT64_C(0x80000000)
? INT32_MIN
: (int32_t)(uint32_t)magnitude;
return (BorlandReal48IntegerResult){candidate, overflow};
}
uint32_t twos_complement = 0U - (uint32_t)magnitude;
int32_t candidate = twos_complement == UINT32_C(0x80000000)
? INT32_MIN
: (int32_t)twos_complement;
return (BorlandReal48IntegerResult){candidate, overflow};
}
/* 1020:1007 — far comparison entry around the near flags-only core. */
int16_t borland_real48_compare(
BorlandReal48 left, BorlandReal48 right)
{
return borland_real48_compare_registers(left, right);
}
static BorlandReal48 require_real48_arithmetic(
BorlandReal48Result result)
{
if (result.divide_by_zero) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_DIVIDE_BY_ZERO);
}
if (result.overflow) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_FLOAT_OVERFLOW);
}
return result.value;
}
/* 1020:0fe5 — far Add wrapper; carry maps to Runtime Error 205. */
BorlandReal48 borland_real48_add(
BorlandReal48 left, BorlandReal48 right)
{
return require_real48_arithmetic(
borland_real48_add_registers(left, right));
}
/* 1020:0feb — far Subtract wrapper around the sign-toggle entry. */
BorlandReal48 borland_real48_subtract(
BorlandReal48 left, BorlandReal48 right)
{
return require_real48_arithmetic(
borland_real48_subtract_registers(left, right));
}
/* 1020:0ff1 — copy AX:BX:DX to CX:SI:DI, then share Multiply. */
BorlandReal48 borland_real48_square(BorlandReal48 value)
{
return require_real48_arithmetic(
borland_real48_multiply_registers(value, value));
}
/* 1020:0ff7 — far Multiply wrapper; carry maps to Runtime Error 205. */
BorlandReal48 borland_real48_multiply(
BorlandReal48 left, BorlandReal48 right)
{
return require_real48_arithmetic(
borland_real48_multiply_registers(left, right));
}
/* 1020:0ffd — denominator zero is Error 200; overflow is Error 205. */
BorlandReal48 borland_real48_divide(
BorlandReal48 left, BorlandReal48 right)
{
return require_real48_arithmetic(
borland_real48_divide_registers(left, right));
}
/* 1020:100b — far integer-to-Real48 entry around 1020:0f3b. */
BorlandReal48 borland_i32_to_real48(int32_t value)
{
return borland_i32_to_real48_registers(value);
}
/* 1020:100f — CH=0 Trunc entry sharing the error tail at 101f with Round. */
int32_t borland_real48_truncate_to_i32(BorlandReal48 value)
{
BorlandReal48IntegerResult converted =
borland_real48_to_i32_registers(value, false);
if (converted.overflow) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_INVALID_FLOAT);
}
return converted.value;
}
/* 1020:1017 — CH=1 Round entry; carry becomes Runtime Error 207. */
int32_t borland_real48_round_to_i32(BorlandReal48 value)
{
BorlandReal48IntegerResult converted =
borland_real48_to_i32_registers(value, true);
if (converted.overflow) {
borland_runtime_error(BORLAND_RUNTIME_ERROR_INVALID_FLOAT);
}
return converted.value;
}