128.128坚固的未签名固定点划分

发布于 2025-01-30 18:32:34 字数 1118 浏览 1 评论 0原文

我目前正在尝试找出一种在两个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施加到较大的UINT类型中,左移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;
    }
}

任何人都知道实现这一目标的最佳方法,甚至只是对如何做的概念解释,这将不胜感激。提前致谢!

I am currently trying to figure out a concrete way to perform fixed point division on two 128.128 uint256 numbers. This seems like a fairly straightforward thing, but haven't been able to code a solution up.

For two 64.64 fixed point numbers the following works just fine.

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);
    }
}

But the same logic does not hold for uint256 128.128 fixed point numbers since you cannot cast x into a larger uint type to left shift x. This is my sad attempt at solving this for 128.128 which doesn't include the correct decimals in the output, but my attempt does include the correct values left of the decimal.

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;
    }
}

Does anyone know the best way to accomplish this, or even just a conceptual explanation of how to do it would be super appreciated. Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

许你一世情深 2025-02-06 18:32:34

好吧,所以我将在这里为下一个家伙发布解决方案。这里的关键是您可以将共同点分解为两个添加剂部分的最明显的事实之一。例如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精度。

Okay, so I'll post the solution here for the next guy. The key here is one of the more obvious facts that you can break up a fraction with a common denominator into two additive parts. For example 12.525/9.5= (12/9.5)+(.525/9.5) with this in mind we have a way to break up our numbers into 2 uint256 numbers and just concatenate them with some fancy shifting.

    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;
        }
    }

This is one solution, that seems to be working so long as the require criterion are met. There are almost undoubtedly optimization improvements to be made. But I have tested this on some real data, and it seems to be accurate to 128.128 precision.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文