11// SPDX-License-Identifier: CAL
22pragma solidity ^ 0.8.25 ;
33
4- import {ExponentOverflow, Log10Negative, Log10Zero} from "../../error/ErrDecimalFloat.sol " ;
4+ import {ExponentOverflow, Log10Negative, Log10Zero, MulDivOverflow } from "../../error/ErrDecimalFloat.sol " ;
55import {
66 LOG_TABLES,
77 LOG_TABLES_SMALL,
@@ -10,6 +10,7 @@ import {
1010 ANTI_LOG_TABLES_SMALL
1111} from "../../generated/LogTables.pointers.sol " ;
1212import {LibDecimalFloat} from "../LibDecimalFloat.sol " ;
13+ import {console2} from "forge-std/console2.sol " ;
1314
1415error WithTargetExponentOverflow (int256 signedCoefficient , int256 exponent , int256 targetExponent );
1516
@@ -61,6 +62,11 @@ int256 constant MAXIMIZED_ZERO_SIGNED_COEFFICIENT = NORMALIZED_ZERO_SIGNED_COEFF
6162/// @dev The exponent of maximized zero.
6263int256 constant MAXIMIZED_ZERO_EXPONENT = NORMALIZED_ZERO_EXPONENT;
6364
65+ /// @dev The signed coefficient of minimized zero.
66+ int256 constant MINIMIZED_ZERO_SIGNED_COEFFICIENT = 0 ;
67+ /// @dev The exponent of minimized zero.
68+ int256 constant MINIMIZED_ZERO_EXPONENT = 0 ;
69+
6470library LibDecimalFloatImplementation {
6571 /// Negates and normalizes a float.
6672 /// Equivalent to `0 - x`.
@@ -190,14 +196,129 @@ library LibDecimalFloatImplementation {
190196 {
191197 unchecked {
192198 (signedCoefficientA, exponentA) = maximize (signedCoefficientA, exponentA);
193- (signedCoefficientB, exponentB) = normalize (signedCoefficientB, exponentB);
199+ (signedCoefficientB, exponentB) = maximize (signedCoefficientB, exponentB);
194200
195- int256 signedCoefficient = signedCoefficientA / signedCoefficientB;
196- int256 exponent = exponentA - exponentB;
201+ uint256 signedCoefficientAAbs;
202+ if (signedCoefficientA < 0 ) {
203+ if (signedCoefficientA == type (int256 ).min) {
204+ signedCoefficientAAbs = uint256 (type (int256 ).max) + 1 ;
205+ } else {
206+ signedCoefficientAAbs = uint256 (- signedCoefficientA);
207+ }
208+ } else {
209+ signedCoefficientAAbs = uint256 (signedCoefficientA);
210+ }
211+ uint256 signedCoefficientBAbs;
212+ if (signedCoefficientB < 0 ) {
213+ if (signedCoefficientB == type (int256 ).min) {
214+ signedCoefficientBAbs = uint256 (type (int256 ).max) + 1 ;
215+ } else {
216+ signedCoefficientBAbs = uint256 (- signedCoefficientB);
217+ }
218+ } else {
219+ signedCoefficientBAbs = uint256 (signedCoefficientB);
220+ }
221+ int256 scale = 1e76 ;
222+ int256 adjustExponent = 76 ;
223+ if (signedCoefficientB / scale == 0 ) {
224+ scale = 1e75 ;
225+ adjustExponent = 75 ;
226+ }
227+ uint256 signedCoefficientAbs = mulDiv (signedCoefficientAAbs, uint256 (scale), signedCoefficientBAbs);
228+ int256 signedCoefficient = (signedCoefficientA ^ signedCoefficientB) < 0
229+ ? - int256 (signedCoefficientAbs)
230+ : int256 (signedCoefficientAbs);
231+ int256 exponent = exponentA - exponentB - adjustExponent;
197232 return (signedCoefficient, exponent);
198233 }
199234 }
200235
236+ /// mulDiv as seen in Open Zeppelin, PRB Math, Solady, and other libraries.
237+ /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
238+ function mulDiv (uint256 x , uint256 y , uint256 denominator ) internal pure returns (uint256 result ) {
239+ // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
240+ // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256
241+ // variables such that product = prod1 * 2^256 + prod0.
242+ uint256 prod0; // Least significant 256 bits of the product
243+ uint256 prod1; // Most significant 256 bits of the product
244+ assembly ("memory-safe" ) {
245+ let mm := mulmod (x, y, not (0 ))
246+ prod0 := mul (x, y)
247+ prod1 := sub (sub (mm, prod0), lt (mm, prod0))
248+ }
249+
250+ // Handle non-overflow cases, 256 by 256 division.
251+ if (prod1 == 0 ) {
252+ unchecked {
253+ return prod0 / denominator;
254+ }
255+ }
256+
257+ // Make sure the result is less than 2^256. Also prevents denominator == 0.
258+ if (prod1 >= denominator) {
259+ revert MulDivOverflow (x, y, denominator);
260+ }
261+
262+ ////////////////////////////////////////////////////////////////////////////
263+ // 512 by 256 division
264+ ////////////////////////////////////////////////////////////////////////////
265+
266+ // Make division exact by subtracting the remainder from [prod1 prod0].
267+ uint256 remainder;
268+ assembly ("memory-safe" ) {
269+ // Compute remainder using the mulmod Yul instruction.
270+ remainder := mulmod (x, y, denominator)
271+
272+ // Subtract 256 bit number from 512-bit number.
273+ prod1 := sub (prod1, gt (remainder, prod0))
274+ prod0 := sub (prod0, remainder)
275+ }
276+
277+ unchecked {
278+ // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow
279+ // because the denominator cannot be zero at this point in the function execution. The result is always >= 1.
280+ // For more detail, see https://cs.stackexchange.com/q/138556/92363.
281+ uint256 lpotdod = denominator & (~ denominator + 1 );
282+ uint256 flippedLpotdod;
283+
284+ assembly ("memory-safe" ) {
285+ // Factor powers of two out of denominator.
286+ denominator := div (denominator, lpotdod)
287+
288+ // Divide [prod1 prod0] by lpotdod.
289+ prod0 := div (prod0, lpotdod)
290+
291+ // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.
292+ // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.
293+ // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693
294+ flippedLpotdod := add (div (sub (0 , lpotdod), lpotdod), 1 )
295+ }
296+
297+ // Shift in bits from prod1 into prod0.
298+ prod0 |= prod1 * flippedLpotdod;
299+
300+ // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
301+ // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
302+ // four bits. That is, denominator * inv = 1 mod 2^4.
303+ uint256 inverse = (3 * denominator) ^ 2 ;
304+
305+ // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
306+ // in modular arithmetic, doubling the correct bits in each step.
307+ inverse *= 2 - denominator * inverse; // inverse mod 2^8
308+ inverse *= 2 - denominator * inverse; // inverse mod 2^16
309+ inverse *= 2 - denominator * inverse; // inverse mod 2^32
310+ inverse *= 2 - denominator * inverse; // inverse mod 2^64
311+ inverse *= 2 - denominator * inverse; // inverse mod 2^128
312+ inverse *= 2 - denominator * inverse; // inverse mod 2^256
313+
314+ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
315+ // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
316+ // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
317+ // is no longer required.
318+ result = prod0 * inverse;
319+ }
320+ }
321+
201322 /// Add two floats together.
202323 ///
203324 /// Note that because the input values can have arbitrary exponents that may
@@ -367,14 +488,9 @@ library LibDecimalFloatImplementation {
367488 return signedCoefficientA == signedCoefficientB;
368489 }
369490
370- /// Inverts a float. Equivalent to `1 / x` with modest gas optimizations .
491+ /// Inverts a float. Equivalent to `1 / x`.
371492 function inv (int256 signedCoefficient , int256 exponent ) internal pure returns (int256 , int256 ) {
372- (signedCoefficient, exponent) = normalize (signedCoefficient, exponent);
373-
374- signedCoefficient = 1e76 / signedCoefficient;
375- exponent = - exponent - 76 ;
376-
377- return (signedCoefficient, exponent);
493+ return div (1e76 , - 76 , signedCoefficient, exponent);
378494 }
379495
380496 /// log10(x) for a float x.
@@ -535,6 +651,27 @@ library LibDecimalFloatImplementation {
535651 }
536652 }
537653
654+ // function minimize(int256 signedCoefficient, int256 exponent) internal pure returns (int256, int256) {
655+ // unchecked {
656+ // if (signedCoefficient == 0) {
657+ // return (MINIMIZED_ZERO_SIGNED_COEFFICIENT, MINIMIZED_ZERO_EXPONENT);
658+ // }
659+
660+ // int256 initialExponent = exponent;
661+
662+ // while (signedCoefficient % 10 == 0) {
663+ // signedCoefficient /= 10;
664+ // exponent += 1;
665+ // }
666+
667+ // if (initialExponent > exponent) {
668+ // revert ExponentOverflow(signedCoefficient, exponent);
669+ // }
670+
671+ // return (signedCoefficient, exponent);
672+ // }
673+ // }
674+
538675 function maximize (int256 signedCoefficient , int256 exponent ) internal pure returns (int256 , int256 ) {
539676 unchecked {
540677 if (signedCoefficient == 0 ) {
0 commit comments