128.128固体中的无符号不动点分割



我目前正试图找出一种具体的方法来对两个128.128 uint256数字进行定点除法。这似乎是一个相当简单的事情,但我还没有能够编码解决方案。

对于两个64.64不动点数,下面的工作很好。

function div64x64 (uint128 x, uint128 y) internal pure returns (uint128) {
unchecked {
require (y != 0);

uint256 answer = (uint256 (x) << 64) / y;
require (answer <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return uint128 (answer);
}
}

但是同样的逻辑并不适用于uint256 128.128固定点数,因为你不能将x转换成一个更大的int类型来左移x。这是我为128.128解决这个问题的悲哀尝试,它在输出中不包括正确的小数,但我的尝试确实包括小数左边的正确值。

function div128x128 (uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
require (y != 0);
uint256 xInt = x>>128;
uint256 xDecimal = x<<128;
uint256 yInt = y>>128;
uint256 yDecimal = y<<128;
uint256 hi = ((uint256(xInt) << 64)/yInt)<<64;
uint256 lo = ((uint256(xDecimal)<<64)/yDecimal);

require (hi+lo <= MAX_128x128);
return hi+lo;
}
}

有谁知道最好的方法来实现这一点,或者甚至只是一个概念性的解释,如何做到这一点将是非常感激的。提前感谢!

好的,我将把解决方案贴在这里给下一个家伙。这里的关键是一个更明显的事实,你可以把一个公分母的分数分解成两个相加的部分。例如12.525/9.5= (12/9.5)+(.525/9.5),考虑到这一点,我们有一种方法可以将我们的数字分成2个uint256数字,然后用一些花哨的移位将它们连接起来。

function div128x128 (uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
//Require denominator != 0
require (y != 0);
// xDec = x & 2**128-1 i.e 128 precision 128 bits of padding on the left
uint256 xDec = x & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
//xInt x *2**-128 i.e. 128 precision 128 bits of padding on the right
uint256 xInt = x >> 128;
//hi = xInt*2**256-1 /y ==> leave a full uint256 of bits to store the integer representation of the fractional decimal with 128.128 precision
uint256 hi = xInt*(MAX_128x128/y);
//xDec*2**256-1 /y ==> leave full uint256 of bits to store the integer representation of fractional decimal with 128.128 precision, right shift 128 bits since output should be the right 128 bits of precision on the output
uint256 lo = (xDec*(MAX_128x128/y))>>128;
/*Example: 12.525/9.5 := 12/9.5 + .525/9.5<-- legal to break up a fraction into additive pieces with common deniminator in the example above just padding to fit 128.128 output in a uint256
*/
require (hi+lo <= MAX_128x128);
return hi+lo;
}
}

这是一种解决方案,只要满足需求标准,似乎就可以工作。几乎毫无疑问,需要进行优化改进。但我已经在一些真实数据上测试过了,它似乎精确到128.128的精度。

最新更新