基本介绍时至今日,人们对阿蒂斯atis也有着很多的依赖性,对产品的预期也越来越高。
金融数学始于百分比。的百分比是多少?的多少百分比是?我们都知道答案:的百分比是×÷,是×÷百分比。这是学校学的数学。......
基本介绍
金融数学始于百分比。的百分比是多少?的多少百分比是?我们都知道答案:的百分比是×÷,是×÷百分比。这是学校学的数学。
上面的公式是求解比例的特殊情况。通常比例是以下形式的方程:÷ = ÷,要求解比例,就是要找到一个知道其他三个值的值。例如可以从,和中找到,如下所示: = ×÷。
正如在上一篇文章中所展示的那样,在主流编程语言中简单明了,在s中,如此简单的计算令人惊讶地具有挑战性。这有两个原因:)实体不支持分数;)s中的数字类型可能会溢出。
在j中,可以这样简单地计算×÷: */ 。可靠地,这样的表达式不会通过安全审核,因为对于足够大的和乘法可能会溢出,因此计算结果可能不正确。使用sm并没有多大帮助,因为即使最终计算结果适合位,它也会使事务失败。在上一篇文章中,我们称这种情况为“幻像溢出”。在像 /* 或 /* 之类的乘法之前进行除法可以解决幻像溢出问题,但可能导致精度降低。
在本文中,我们发现s中有哪些更好的方法来处理百分比和比例。
迈向全比例
本文的目标是在s中实现以下功能:
d ( ,,)
()
这将计算×÷,将结果四舍五入,并在为零的结果不适合的情况下抛出。让我们从以下简单的解决方案开始:
d ( ,,)
()
{
*/ ;
}
此解决方案基本上满足大多数要求:似乎计算×÷,将结果四舍五入,并在为零的情况下抛出。但是,存在一个问题:它实际计算的是× 2÷。这就是s中乘法溢出的工作方式。当乘法结果不适合位时,仅返回结果的最低位。对于和较小的值,当× &;2时,没有差异,但是对于较大的和,这将产生错误的结果。所以第一个问题是:
我们如何防止溢出?
防止s中乘法溢出的常用方法是使用sm库中的函数:
d ( ,,)
()
{
(, ) / ;
}
该代码保证了正确的结果,所以现在所有的要求似乎都满足了,对吧?没那么快。
要求是在结果不适合的情况下还原,并且此实现似乎可以满足要求。但是即使最终结果合适,当×不适合时,此实现也会还原。我们称这种情况为“幻像溢出”。在上一篇文章中,我们展示了如何以精确度为代价解决幻像溢出,但是该解决方案在这里不起作用,因为我们需要精确的精确结果。
由于无法还原幻像溢出,因此
我们如何避免幻像溢出保持精度?
让我们进行以下替换: = × + 和 = × + ,其中,,和是整数,≤&;和≤&;。然后:
×÷=
(×+)×(×+)÷=
(××2+(×+×)×+×)÷=
××+×+×+×÷
通过分别将和除以,可以将值,,和计算为商和余数。
因此,该函数可以这样重写:
d ( ,,)
()
{
=/ ; =% ; //=*+
=/ ; =% ; //=*+
**+*+*+*/ ;
}
在这里,我们使用普通的+和*运算符以提高可读性,而真实代码应使用sm函数来防止真实(即非幻像)溢出。
在此实现中,幻像溢出仍然是可能的,但仅在最后一项中:*/。但是由于和都小于,因此保证了该代码在≤时能正常工作,因此可以保证×适合位。因此可以在已知不超过^的情况下使用此实现。一个常见的例子是位小数的定点乘法:×÷1?。
我们如何才能完全避免幻影溢出?
幻像溢出问题的根源在于中间乘法结果不适合位。因此,让我们使用更广泛的类型。s本身不支持大于位的数字类型,因此我们将不得不模拟它们。我们基本上需要两个操作:×→和÷→。
由于两个位无符号整数的乘积不能超过位,因此较宽的类型必须至少为位宽。我们可以通过两个位无符号整数对分别模拟位无符号整数,这两个整数分别持有整个位数字的低位和高位。
因此,代码可能如下所示:
d ( ,,)
()
{
( ,) = m (, );
d (, , );
}
这里m函数将两个位无符号整数相乘,并将结果作为位无符号整数分成两个位部分返回。函数d将位无符号整数相除,以两个位无符号整数形式传递,但以位无符号整数形式传递,并以位无符号整数形式返回结果。
让我们以学校数学的方式实现这两个函数:
m ( ,)
( ,)
{
=(); =&;&; ;
=(); =&;&; ;
=* ; =* ;
=* ; =* ;
=();
= ( &;&; ) +() +();
=() + ( &;&; ) + ( &;&; );
= ( &;&; );
=+ ( &;&; );
= ( &;&; ) ++ ( &;&; );
}
和
d ( ,,)
( ) {
( &; );
s = sb ();
z = ;
(s &;= ) s = ;
{
s -= ;
z = (z -&;&; s) + ;
}
( &; )
{
s = sb () + ;
s =- s;
= (( &;&; s) + ( &;&; s)) / z;
(s &; s)&;&;= (s - s);
&;&;= (s - s);
+= ;
( ,) = m (, );
-= ;
( &; )-= ;
-= ;
}
+=/ ;
}
这里的sb是一个函数,它返回参数最高有效位的从零开始的索引。此功能可以通过以下方式实现:
sb ( ) ( ) {
( &; );
( &;= **) {&;&;= ;+= ; }
( &;= **) {&;&;= ;+= ; }
( &;= **) {&;&;= ;+= ; }
( &;= **) {&;&;= ;+= ; }
( &;= **) {&;&;= ;+= ; }
( &;= **) {&;&;= ;+= ; }
( &;= **) {&;&;= ;+= ; }
( &;= **) {&;&;= ;+= ; }
}
上面的代码相当复杂,可能需要解释,但我们现在将跳过解释,而将重点放在不同的问题上。这段代码的问题是,每次调用d函数大约要消耗.k ,这是相当多的。所以,
我们可以便宜吗?
以下代码基于r b描述的令人兴奋的数学发现。
首先,我们重写m函数:
m ( ,)
( ,)
{
=(, ,(-));
=* ;
=- ;
( &; )-= ;
}
每一次m调用可以节省大约。
然后我们重写d函数:
d ( ,,)
() {
( ,) = m (, );
( &; );
=(, , );
( &; )-= ;
-= ;
=&; -;
/= ;
/= ;
+=* ((-) /+ );
= ;
*=-* ;
*=-* ;
*=-* ;
*=-* ;
*=-* ;
*=-* ;
*=-* ;
*=-* ;
* ;
}
这个实现每次d调用只消耗大约 ,并且可以进一步优化。比学校数学方法好倍。很好!但是,实际上必须获得数学博士学位才能编写这样的代码,并且并非每个问题都具有这样的数学解决方案。如果可以的话,事情会简单得多。
在s中使用浮点数
正如我们在本文开头所说的,在js中,只需编写一个*/,其余部分由语言来处理。如果我们能在s上做同样的事呢?
实际上我们可以。虽然核心语言不支持浮点,但有些库支持。例如使用abdkmq库,可以编写:
d ( ,,)
() {
abdkmq.ui (
abdkmq. (
abdkmq. (
abdkmq.ui (),
abdkmq.ui ()
),
abdkmq.ui ()
)
);
}
不像js那样优雅,不像解决方案那样便宜(甚至比学校的数学方法更具扩展性),但是非常简单和精确,因为这里使用的四倍精度浮点数有大约个有效小数。
此实现方式消耗的气体有一半以上用于将值转换为浮点数和浮点数,比例计算本身仅消耗约.k 。因此在所有智能合约中使用浮点数可能比混合整数和浮点数便宜得多。
结论
由于溢出和缺少分数支持,因此百分比和比例在s中可能具有挑战性。但是,各种数学技巧都可以正确有效地解决比例问题。