The fixed-point series run on System.Numerics.BigInteger, and a fixed-point value is read back as a decimal by scaling to a power of ten - #1364
Merged
Conversation
…-point value is read back as a decimal by scaling to a power of ten #1346 and #1347 put the logarithm, the exponential, the sine, the cosine and the arctangent into fixed point on PeterO's EInteger. Measured against mpmath on the same machine the transcendental rows were still nine to seventeen times behind, and the reason is the integer type: one multiply of two hundred-digit integers is 1,271 ns in EInteger and 109 ns in System.Numerics.BigInteger (8,087 against 1,364 at five hundred digits, 75,850 against 12,036 at two thousand), and the BCL's is at parity with CPython's int, which is what mpmath's digits live in. The series run on BigInteger now, converted once on the way in and once on the way out as two's-complement bytes, and the way out no longer multiplies by 5^bits and asks EDecimal to round a number of four times the digits: the fixed-point integer is scaled to a power of ten six digits past the precision in BigInteger, and only the rounding is EDecimal's. The hundred-digit values are the ones pinned before, to the last digit. EvalTrig 153 us / 260,728 B -> 83 us / 164,728 B EvalTrigPrecise 2.16 ms / 2,525,707 B -> 1.05 ms / 718,778 B EvalTranscendentalFresh 83 us / 128,664 B -> 33 us / 59,136 B SolveEasy 1.19 ms / 1,675,487 B -> 0.49 ms / 981,996 B SimplifyHard -3.9% B every other entry within 0.1% Alone, one probe on both builds: at a hundred digits sin(x) is 15 us where it was 47, ln(x) 18 where it was 52, e^x 10 where it was 32, arctan(x) 25 where it was 49; at five hundred digits sin(x) 228 us where it was 1,273, ln(x) 777 where it was 3,921; at two thousand sin(x) 11.7 ms where it was 40.7 and ln(x) 26 where it was 121. The gate's baseline is from this run; the performance log has the entry. Four suites green (11,345 / 134 / 18 / 41). Part of #1338. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
This was referenced Sep 15, 2026
Rafael-SOWNet
added a commit
that referenced
this pull request
Sep 16, 2026
… before the exact search, and reads a value of up to four thousand digits (#1365) * The rational pre-check confirms a double's maybe in the double-double before the exact search, and reads a value of up to four thousand digits EvalTrig is sin 1 + cos 1 + tan 1, and after #1364 fifty of its eighty-three microseconds were Real.Create deciding that sin 1 is not a small rational, while cos 1 was decided in a fifth of one. The cheap decision of #1342 runs the continued fraction in a double first and answers "may be" where a remainder is within the double's own error of the next integer; for sin 1 that is the twelfth level, where the error has grown to a hundredth, and the answer went straight to the exact hundred-digit search instead of to the double-double, whose error there is ten to the minus twelve and which refuses in under a microsecond. A double's yes is confirmed in the double-double now, always. The reading of a value into the double-double scaled by two halves of its binary shift, of which half of a thousand-digit value's is 2^1608, an infinity: every Real.Create past about six hundred and fifty digits went to the exact search, 5.7 ms each at two thousand. The scaling is in as many pieces as keep each factor in range, up to four thousand digits, past which the error the search assumes would no longer hold. Nothing a value downcasts to changes; the twelve-thousand-rational agreement test and a two-thousand-digit one say so. EvalTrig 83 us / 164,728 B -> 37 us / 82,104 B EvalTrigPrecise 1.05 ms / 718,778 B -> 0.62 ms / 525,289 B every other entry 0.0% Alone, Real.Create of sin 1's hundred digits is 0.5 us where it was 49, and of two thousand digits 0.3 us where it was 5,660. The gate's baseline is from this run; the performance log has the entry. Four suites green (11,345 / 134 / 18 / 41). Part of #1338. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * The gate's baseline is the run of the previous commit Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rafael-SOWNet
added a commit
that referenced
this pull request
Sep 16, 2026
…ths, the cosine is the sine's root at the reduced argument, and a square root is the integer one with a sticky digit (#1366) * The logarithm and the arctangent are reduced by a table of sixty-fourths, the cosine is the sine's root at the reduced argument, and a square root is the integer one with a sticky digit After #1364 the remaining factor to mpmath was the term count: eighty artanh terms for a logarithm at a hundred digits, forty-seven for an arctangent after three square-root halvings, and two series -- the sine's and the cosine's -- for either. The logarithm's mantissa, already within [1/sqrt 2, sqrt 2], is divided by the nearest 1 + j/64, whose logarithm the constant cache holds (built outward from ln 1 = 0 when first asked, one short series a step), so the series runs on a quotient within 1/128 of one: twenty-five terms. The arctangent's argument, within [0, 1], is brought within 1/128 of zero by the nearest j/64 the same way, arctan x = arctan c + arctan((x - c)/(1 + xc)): thirty terms and no square root. The cosine at the sine's reduced argument, which is within a twentieth of zero, is sqrt(1 - sin^2) and cancels nothing; the other way round is what lost half the digits in #1342. And the square root of a decimal is the integer square root of its mantissa padded to twice the digits, with a sticky digit so that the rounding to the context is the correct one in every mode, as PeterO's is -- Newton from the root of the top half of the bits, three divisions at the full width where a power of two above the root took one per bit of the exponent. The hundred-digit values are the ones pinned before, to the last digit. EvalTranscendentalFresh 33 us / 59,136 B -> 16 us / 34,608 B EvalTrig 37 us / 82,104 B -> 32 us / 69,792 B EvalTrigPrecise 617 us / 525,289 B -> 406 us / 336,360 B SolveEasy 491 us / 981,996 B -> 390 us / 783,622 B SolveHard 11,708,080 B -> 10,053,640 B every other entry within 1.3% Alone, one probe on both builds: at a hundred digits ln is 8.4 us where it was 18.0, arctan 7.7 where it was 24.6, sin 13.1 where it was 15.2; at five hundred ln 241 us where it was 777, sin 141 where it was 228, and the square root 22 where PeterO's is 41; at two thousand digits the square root 174 us where PeterO's is 441. The gate's baseline is from this run; the performance log has the entry. Four suites green (11,345 / 134 / 18 / 41). Part of #1338. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura * The gate's baseline is the run of the previous commit Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Sep 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#1346 and #1347 put the logarithm, the exponential, the sine, the cosine and the arctangent into fixed point on PeterO's
EInteger. Measured against mpmath on the same machine (#1338, the table), the transcendental rows were still 9–17× behind, and the reason is the integer type: one multiply of two hundred-digit integers is 1,271 ns inEIntegerand 109 ns inSystem.Numerics.BigInteger(8,087 vs 1,364 at 500 digits, 75,850 vs 12,036 at 2,000), and the BCL's is at parity with CPython'sint, which is what mpmath's digits live in.The series run on
BigIntegernow, converted once on the way in and once on the way out as two's-complement bytes (EInteger.ToBytes(littleEndian: true)/EInteger.FromBytes), and the way out no longer multiplies by5^bitsand asksEDecimalto round a number of four times the digits:FromFixedscales the fixed-point integer to a power of ten six digits past the precision inBigInteger(the powers cached per context) and leaves only the rounding toEDecimal. That reading alone was 5 of the 25 µs at 100 digits and 65 of 228 at 500. The decimal layer above is untouched; no public API changes.The hundred-digit values are the ones pinned before, to the last digit (
NumericDigits,HighPrecisionFunctionsTest) — noBREAKING-CHANGESentry.EvalTrigEvalTrigPrecise(500 digits)EvalTranscendentalFreshSolveEasySimplifyHardAlone, one probe on both builds (best of seven batches, tiered compilation off, a fresh node per call since an entity caches its
Evaled):sin(x)ln(x)e^xarctan(x)At 500 digits
sin1,273 → 228 µs,ln3,921 → 777,e^x2,774 → 548; at 2,000 digitssin40.7 → 11.7 ms,ln121 → 26. The remaining factor of 3–6 to mpmath is the term count (eighty artanh terms for a logarithm, twenty-five for a sine), which is the argument-reduction step next.Baseline from this run; the performance log has the entry. Four suites green (11,345 / 134 / 18 / 41).
Part of #1338.
🤖 Generated with Claude Code
https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura