令f为二进制分数:
假如x是小数怎么办?尽量该要领简朴明白,但其gas耗损量为O(n),因此很是昂贵。这是合用于256位正整数x的改造版本:
因此,假如f是上面显示其二进制暗示形式的数字,则
这种改造的实施方案在最坏的环境下耗损了约600gas:比原始的未经优化的gas淘汰25倍。幸运的是,ABDK库已经筹备好对64.64位二进拟定点四精度二进制浮点数利用二进制对数实现。
因此,假如期望的功效精度为M位,那么我们可以忽略f的二进制暗示形式的那些位,这些位的位置比点后的M个二进制位置更远。这样我们最多需要预先计较的M个把戏因子来计较指数。
我们先容了利用对数和指数函数有效执行的持续复利计较的实际用例。
if (x >= 2**4) { x >>= 4; n += 4; }
delta = div (delta, TWO)) {
对 数
以下是编写的代码,仿佛Solidity自己支持小数:
因此
for (n = 0; x > 1; x >>= 1) n += 1;因数
对付b = 2,这给我们:
在本文中,我们将展示如安在Solidity中有效地实现以2为底的对数和指数函数,如何将这些以2为底的函数转换为相应的自然(以e为底)函数,以及在DeFi应用措施中这些函数的实际用例是什么?。可以预先计较,无需在运行时举办计较:
可以将其硬编码到实施中,而无需在运行时举办计较。
假设n是x的二进制对数的整数部门,则对数的小数部门可以这样计较:
指 数
if (x >= 2**2) { x >>= 2; n += 2; }
此刻当我们完成对数后,让我们切换到
此刻当我们知道如何计较二进制对数时,
如何计较Solidity中二元对数的整数部门?
对付二进制浮点数甚至更简朴,因为在上面的公式中y是尾数便是1且指数便是x的二进制浮点数。
假如X是小数怎么办?
此刻请留意,
这是合用于正整数x的简朴要领:
让我们从二进制(以2为底)对数开始。x的二进制对数是y,使得:
然后
由于我们已经知道如何计较以2为底的对数和指数函数,因此我们可以利用任意底数来计较指数函数。
}
if (x >= 2) { result += delta; x /= 2; }
for (delta = ONE;
简 介
因此可以将二进拟定点或浮点数的二进制对数计较为尾数加上指数的二进制对数。只要指数是整数,沟通的公式也合用于对数的整数部门。
if (x >= 2**1) { /* x >>= 1; */ n += 1; }
x = mul (x, x);
if (x >= 2**8) { x >>= 8; n += 8; }
请留意,这些公式合用于除一个以外的任意正数基数,因此我们可以选择便于实现的基数。
获得
在每次迭代中,我们都应用前一个法则:将x的值平方,然后将delta的值减半。假如在某个点x的值变得大于或便是2,则我们应用后一个法则:将delta加到result并将x的值减半。我们反复轮回直到增量降到所需的precision以下为止,因为举办计较不会对result发生任何重大影响。我们还描写了如何通过base-2函数实现基于任意对数和指数的函数。
y = 1 << x
为了计较自然对数(以e为底)和民众对数(以10为底),,我们可以利用以下法则:
在本文中,我们展示了如安在Solidity中有效地计较以2为底的对数和指数函数以二进拟定点和浮点数。
我们知道,对付除一个以外的任意正x和任意正b,以下条件创立:
if (x >= 2**16) { x >>= 16; n += 16; }
只能计较一次,大概是在链外,然后再利用,这将使此公式越发有效。
同样让我们从以2为底的幂开始,即
让我们将x的一个小数值分成整数部门n和小数部门f:
结 论
x = div (x, TWO);
for (delta = 1; delta >= precision; delta /= 2) {
不幸的是,Solidity自己不支持分数,因此实际代码如下所示:
可是这仅合用于x的整数和非负值。并且这并不是最有效的一种,因为利用移位操纵会更自制:
Solidity具有**运算符,因此显而易见的办理方案是:
if (x >= 2**128) { x >>= 128; n += 128; }
此刻,当我们知道如作甚整数部门提供资金时,
x *= x;
以2为底的指数是好的,可是那么任意基数的指数呢?
留意,只要
对付二进制浮点数,环境要巨大一些,因为尾数m可通过大的负指数e右移。因此此类浮点数的二进制暗示形式如下所示:在Solidity语言的焦点中没有分数,可是有几种要领可以模仿这些数字。二进拟定点和二进制浮点。两种方法都暗示分数x,如下所示:
在此,r是单个时间单元的利率,t是要计较其复利的时距离断的长度。请留意在牢靠利率的环境下,
那自然对数和民众对数呢?
个中ONE,TWO,两个,add,mul,div和gte是常量和函数,它们模仿某种分数数字并对其举办算术运算。
在对这些方程的阁下部门求幂之后,我们获得:
if (gte (x, TWO)) {}
y = x >= 0 ? 1 << x : 1 >> -x
请留意,假如
因此可以将计较二进制对数的小数部门推导出来计较介于1(含)和2(不含)之间的数字的二进制对数。为了举办此计较,我们将利用以下两个法则:
显然,要使y存在,x的值必需为正。
所以n是x的二进制对数的整数部门。因此我们的第一个问题是:
留意:
if (x >= 2**32) { x >>= 32; n += 32; }在下一篇文章中,我们将显示DeFi应用措施中对数和指数的更多用例,下一个主题是:Bancor公式。
幸运的是,对付介于0和1之间的任何f
该公式可用于有效计较持续复利:可以在ABDK库源代码中找到针对二进拟定点和浮点数的基于2指数函数的即用型实现。
然后
因此,对付任意y:
y = 2**x对数函数与指数函数(对数函数是指数函数的倒数)一起,可以把乘法酿成加法,更重要的是,可以把指数函数酿成乘法。由于以下两个法则,这是大概的: result = add (resukt, delta);
移位大概尚有助于x的负值:
if (x >= 2**64) { x >>= 64; n += 64; }
二进制对数的小数部门呢?
由于Solidity自己不支持分数,因此任何负x都将导致零功效,这没有太大意义。可是假如将定点暗示形式1替换为整数1,则此代码将变得越发公道。
因此,本文的重点是指数和对数。
然后
个中m和e是整数。值m称为尾数,e称为指数。二进拟定点数和浮点数的区别在于,定点数的指数是一个预界说的常数,凡是为负数,因此只需存储尾数;而浮点数的指数是可变的,因此必需与尾数一起存储。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。