js 大数精度_PHP中的任意精度和大数

js 大数精度

Mathematical questions and applications always trigger me. Recently I just finished a book by Stephen Hawking “God Created The Integers” and being able to “talk” to those great mathematicians in history thrills me. This is the main reason I decided to write about this topic.

数学问题和应用总是激发我。 最近,我刚读完了斯蒂芬·霍金(Stephen Hawking)的书《 上帝创造了整数 》,并且能够与历史上的那些伟大数学家“交谈”,这让我感到非常激动。 这是我决定写此主题的主要原因。

In this article, we will review the PHP capability to provide arbitrary precision number calculation / big integer calculation by reviewing 3 PHP modules: GMP, BC Math and php-bignumbers. We will demonstrate two real-world examples to see the powers/limitations of each. The first one will be calculating PI to arbitrary precision – well, for the sake of the article, we will restrict the precision, say, to 1000 digits; the second will be a simple demonstration on RSA encryption/decryption.

在本文中,我们将通过回顾3个PHP模块( GMPBC Mathphp-bignumbers)来回顾PHP提供任意精度数字计算/大整数计算的功能 。 我们将演示两个实际示例,以了解每个示例的功能/局限性。 第一个将计算PI到任意精度–好吧,出于本文的考虑,我们将精度限制在1000位以内。 第二个是关于RSA加密/解密的简单演示。

Let’s get started.

让我们开始吧。

制备 (Preparation)

To get the GMP PHP module, simply issue the following command in your terminal on any Unix system (or install it manually if on Windows – but please use Vagrant!):

要获取GMP PHP模块,只需在任何Unix系统上的终端中发出以下命令(或在Windows上手动安装,但请使用Vagrant !):

sudo apt-get install php5-gmp

须藤apt-get install php5-gmp

php-bignumbers is distributed via Composer. Create a composer.json file and run php composer.phar install after adding the requirement. The php-bignumbers Github site has the detailed information to how to write the composer.json file.

php-bignumbers通过Composer分发。 添加需求后,创建一个composer.json文件并运行php composer.phar installphp-bignumbers Github站点提供了有关如何编写composer.json文件的详细信息。

BC is usually pre-installed and enabled.

BC通常是预先安装并启用的。

After installation, we can test that all are working fine by writing a simple PHP script and running it in the terminal:

安装后,我们可以通过编写一个简单PHP脚本并在终端中运行它来测试所有工具是否工作正常:

<?php

// Below is to test php-bignumber lib
require_once 'vendor/autoload.php'; // Required for autoload

use \Litipk\BigNumbers\Decimal as Decimal;

$one = Decimal::fromInteger(1);
$two= Decimal::fromInteger(2);
$three=Decimal::fromInteger(3);
$seven = Decimal::fromString('7.0');

$a=$one->div($seven, 100); // Should display something like 0.142857142857 .....and the last digit is 9 in consideration of rounding up the 101th digit. 
$b=$two->div($seven, 100);
$c=$three->div($seven, 100);

echo ($c->sub(($a->add($b)))); //Displays 0.00000... to the last digit

echo "\n";

// Now we test GMP

echo gmp_strval(gmp_div("1.0", "7.0")); //Displays 0. Not really useful!
echo "\n";

// Now we test BC

$oneseven=bcdiv('1', '7', 100); // Should display something like 0.142857142857 .....but note the last digit is 8, not 9.
$twoseven=bcdiv('2','7', 100);
$threeseven=bcdiv('3','7', 100);

echo bcsub(bcadd($oneseven, $twoseven,100), $threeseven, 100); // Displays 0.000000000... to the last digit
echo "\n";

The above code will output like below:

上面的代码将输出如下:

alt

In the first and the third output (using php-bignumbers and BC, respectively), they are identical and accurate (1/7+2/7-3/7=0).

在第一和第三输出中(分别使用php-bignumbers和BC),它们是相同且准确的(1/7 + 2 / 7-3 / 7 = 0)。

For GMP, it only handles big integers and does not provide arbitrary precision floating numbers calculation method so it says 1/7=0, a result we can expect for one integer dividing another. For this reason, I won’t use GMP for arbitrary precision demo (PI calculation) and will only use it in the RSA demo.

对于GMP,它仅处理大整数,并且不提供任意精度的浮点数计算方法,因此它表示1/7 = 0,我们可以预期一个整数除以另一个的结果。 因此,我不会将GMP用于任意精度的演示(PI计算),而只会在RSA演示中使用它。

三种库的简要比较 (A brief comparison of three libraries)

php-bignumber:

php-bignumber:

  • New, under development;

    新的,正在开发中;
  • Object Oriented;

    面向对象;
  • More typing to create a number;

    更多输入以创建数字;
  • Limited operators and functions (at the time of writing, it is missing pow function and all other important mathematical function families like trigonometry, factorial, etc);

    有限的运算符和函数(在编写本文时,它缺少pow函数和所有其他重要的数学函数族,例如三角函数,阶乘等);

  • Provides arbitrary precision capability, which is what we needed.

    提供我们需要的任意精度功能。

BC:

公元前:

  • Mature, pre-installed and enabled;

    成熟,已预安装并启用;
  • Not Object Oriented;

    不是面向对象的;
  • 10 functions available, missing all functions as php-bignumber, except pow, and missing log/ln;

    10个可用函数,缺少pow和log / ln除外的所有函数,如php-bignumber;

  • Provides arbitrary precision capability, which is what we needed.

    提供我们需要的任意精度功能。

GMP:

GMP:

  • Mature, easy to install;

    成熟,易于安装;
  • Not Object Oriented;

    不是面向对象的;
  • Over 40 functions available, but all focused on integer manipulation;

    超过40种功能可用,但全部集中在整数操作上;
  • Provides arbitrary precision for integers, not fully what we want.

    为整数提供任意精度,而不是我们想要的精度。

Theoretically, with +-*/ provided, there is actually no limitation to simulate other operations on numbers. It may be easier to expand php-bignumbers than to expand the other two. So I am looking forward to the author of php-bignumbers to add in more functions in the future.

从理论上讲,在提供+-* /的情况下,模拟数字上的其他运算实际上没有任何限制。 扩展php-bignumbers可能比扩展其他两个更容易。 因此,我期待php-bignumbers的作者在将来增加更多功能。

If we are only dealing with integers, and particularly not much with the division (or at least, as we can see in RSA demo, we are more interested in the quotient and remainder), all 3 libs are a good candidate and GMP may be even better as it provides the largest number of functions. But if we are determined to get a floating result with arbitrary precision, GMP is out of consideration and we will rely on BC and php-bignumbers.

如果我们只处理整数,尤其是除法运算不多(或者至少在RSA演示中可以看到,我们对商和余数更感兴趣),那么所有3个库都是不错的选择,而GMP可能是更好,因为它提供了最多的功能。 但是,如果我们确定要以任意精度获得浮动结果,则GMP不在考虑之列,我们将依赖BC和php-bignumbers。

Now, let’s get into the real world demonstration.

现在,让我们进入真实世界的演示。

计算PI (Calculating PI)

PI as an irrational number, its value can be calculated infinitely to any number of digits. The calculation of PI itself is useful in testing the speed of a PC, and testing the optimization of the algorithm.

PI为无理数,其值可以无限地计算为任意位数。 PI本身的计算对于测试PC的速度以及测试算法的优化非常有用。

As this calculation involves floating numbers, we will use BC and php-bignumbers. For the two programs, we will use the simplest way to calculate PI:

由于此计算涉及浮点数,因此我们将使用BC和php-bignumbers。 对于这两个程序,我们将使用最简单的方法来计算PI:

π^2/6=1+1/4+1/9+......+1/(2n-1)^2

π^2/6=1+1/4+1/9+......+1/(2n-1)^2

This is not the fastest way to calculate PI as its convergence speed is a bit slow, but never mind.

这不是计算PI的最快方法,因为它的收敛速度有点慢,但是没关系。

To benchmark the speed of these two libraries, we will set a stopwatch. As I know it is a lengthy process, I will use the PHP built-in time function to get the timestamp and calculate the difference – I can tell you now that the difference is obvious. We also will compare if the two results are identical (not close enough, but identical).

为了测试这两个库的速度,我们将设置一个秒表。 据我所知,这是一个漫长的过程,我将使用PHP内置的time函数来获取时间戳并计算差异–现在,我可以告诉您差异是显而易见的。 我们还将比较两个结果是否相同(距离不够近,但相同)。

The biggest n used in the above formula will be set to 1,999,999. This is to avoid too much time spent on finishing the computation on my PC.

上式中使用的最大n将设置为1,999,999。 这是为了避免在PC上花费太多时间来完成计算。

Also, to avoid extra function call overhead, we will not use any extra user functions. This may create some redundant lines but let’s bear with it.

另外,为避免额外的函数调用开销,我们将不使用任何额外的用户功能。 这可能会创建一些多余的行,但让我们忍受。

I have done some basic optimization in the calculation. More optimization suggestions are more than welcome!

我在计算中做了一些基本的优化。 欢迎提供更多优化建议!

The code (and the RSA code shown later) has been uploaded to Github.

该代码(以及稍后显示的RSA代码)已上传到Github

I have tested the performance (both in terms of speed and accuracy) with different n and the below table shows the summary:

我已经使用不同的n测试了性能(在速度和准确性方面),下表显示了摘要:

alt

Frankly speaking, this result really disappoints me. With a max N set to 2 million, we are only able to achieve an accuracy to the 6th decimal point (3.141592) compared to the real PI. But this is due to the convergence speed of the algorithm itself.

坦白说,这个结果令我非常失望。 将最大N设置为200万,与真实PI相比,我们只能达到小数点后第六位(3.141592)的精度。 但这是由于算法本身的收敛速度。

Both methods (BC and php-bignumbers) demonstrate a high level of identity of the results: for 1000+ digits, they only differ after the 990th digit. This is equivalent to 10E-990 difference, which is sufficient enough for us to put the same level of confidence on the identity of their outputs. In other words, given the same algorithm, these two libs give out the “same” result.

两种方法(BC和php-bignumbers)都证明了结果的高度一致性:对于1000多个数字,它们仅在第990个数字之后才不同。 这相当于10E-990的差异,足以使我们对它们的输出的标识具有相同的置信度。 换句话说,给定相同的算法,这两个库给出的结果“相同”。

However, the speeds are of a huge gap. Roughly, BC takes only 1/3 of the time of that of php-bignumbers. I believe this is because the php-bignumbers lib is spending a lot of overhead on OO-related processing.

但是,速度差距很大。 大约,BC仅花费php-bignumbers时间的1/3。 我相信这是因为php-bignumbers库在与OO相关的处理上花费了很多开销。

Both libs (and also GMP) internally use strings to store arbitrary precision numbers by forming that string to the digits we specified. String manipulation will also slow down the performance. There’s also the fact that BC is written and executed at a low level – in C – while bignumbers is just a high level PHP library.

两个库(以及GMP)在内部都使用字符串来存储任意精度数字,方法是将该字符串形成为我们指定的数字。 字符串操作也会降低性能。 还有一个事实,即BC是用C底层编写和执行的,而bignumbers只是一个高级PHP库。

If we decrease the precision to 100 digits, the time consumed will be tremendously shortened. When n=999,999, 15s and 85s will elapse for BC and php-bignumbers, respectively and the accuracy of the output is still preserved. The results from the two libs will differ from the 95th digit out of 100+ digits. We are still comfortable to say they are identical.

如果我们将精度降低到100位,那么所花费的时间将大大缩短。 当n = 999,999时,BC和php-bignumbers将分别经过15s和85s,并且仍保持输出的准确性。 两个库的结果将与100个以上的数字中的第95个数字不同。 我们仍然很高兴地说它们是相同的。

So the suggestion is, at this stage, BC is still recommended. It provides the same accuracy but is much faster. To save time when doing such arbitrary precision calculation, it is highly recommended to set a lower scale of precision. The time will be roughly 1/10 if the scale is 1/10 (1000 digits costs 128s while 100 digits costs 15s for BC. For php-bignumbers, it is only 1/5 though).

因此,建议在现阶段仍建议使用BC。 它提供相同的精度,但速度要快得多。 为了节省进行任意精度计算的时间,强烈建议设置较低的精度范围。 如果比例为1/10,则时间约为1/10(1000位数字花费128s,而100位数字花费BC 15s。对于php-bignumbers,它仅为1/5)。

Just to bring our discussion to the extreme, I have inserted a few lines of code to see what the result will be if we don’t rely on any libraries and just use the built-in floating numbers.

为了使我们的讨论达到极致,我插入了几行代码以查看如果我们不依赖任何库而仅使用内置浮点数将产生什么结果。

The result is astonishing. When n is set to 999,999, the built-in floating number gives a result of 3.1415916986586, almost identical to what we can get from BC (3.1415916986595…). But guess what? It finishes almost instantaneously!

结果是惊人的。 当n设置为999,999时,内置的浮点数将得出3.1415916986586的结果,几乎与我们从BC(3.1415916986595…)所获得的结果相同。 但猜猜怎么了? 它几乎立即完成!

Thus my conclusion is this: If we don’t really care about the digits at and beyond the 10th digit, we probably shouldn’t use any of the arbitrary libs at all.

因此,我的结论是:如果我们真的不关心第10位及以后的数字,则可能根本不应该使用任何任意lib。

RSA演示 (An RSA demo)

RSA encryption used to be very much trusted but a piece of recent news put it under the spot light, accusing RSA’s possible cooperation with NSA by planting a backdoor inside RSA’s encryption algorithm (here). Nevertheless, the algorithm itself is still worth discussing here.

RSA加密曾经是非常受信任的,但是最近的一则新闻使它受到关注,指责RSA通过在RSA的加密算法中植入后门( 此处 )来与NSA合作。 尽管如此,算法本身仍然值得在这里讨论。

A detailed description of RSA is beyond this article. Interested parties can refer to its WIKI page for a detailed explanation. We will just illustrate the code we write to implement the RSA encryption and decryption.

RSA的详细说明超出了本文的范围。 有兴趣的人士可以参考其WIKI页面以获取详细说明。 我们将仅说明为实现RSA加密和解密而编写的代码。

Note: The code and the steps illustration below is inspired by this article, written in Chinese by a Chinese programmer Mr Ruan.

注意:下面的代码和步骤说明受本文启发, 本文由中国程序员阮先生撰写。

The preparation work for our RSA demo is illustrated as below:

RSA演示的准备工作如下图所示:

alt

We won’t cover the algorithm that is behind the generation of these numbers. So far, we just need to know that there are 6 numbers generated/selected after these steps: p, q, n, φ(n), e and d. We also know the public key is generated as (3233, 17) and private key generated as (3233, 2753).

我们将不讨论这些数字生成背后的算法。 到目前为止,我们只需要知道在这些步骤之后就会生成/选择6个数字:p,q,n,φ(n),e和d。 我们还知道,公钥生成为(3233,17),私钥生成为(3233,2753)。

Encrypting a number (strings should be converted to ASCII or Unicode character by character) is done in the process to find c in the below calculation:

在下面的计算中找到数字c的过程中完成了数字加密(字符串应逐字符转换为ASCII或Unicode字符):

m^e = c (mod n), and m<n

m^e = c (mod n), and m<n

That is, to find the remainder of m^e divided by n.

也就是说,找到m^e除以n的余数。

Let’s say we would like to encrypt the letter ‘A’; its ASCII code is 65, then:

假设我们要加密字母“ A”; 它的ASCII码是65,然后:

65^17 = 2790 (mod 3233)

65^17 = 2790 (mod 3233)

So c=2790. We can send 2790 to my partner and he will use the private key (3233, 2753) to decrypt it. (In practice, we will receive the public key from my partner and he will keep the private key to himself.)

因此, c = 2790。 我们可以将2790发送给我的伴侣,他将使用私钥(3233、2753)对其进行解密。 (实际上,我们将从合作伙伴那里获得公钥,而他将私钥保留给自己。)

The decryption will be like solving the following:

解密就像解决以下问题:

c^d=m (mod n)

c^d=m (mod n)

That is, to find out the remainder (m) of c^d divided by n. Thus,

也就是说,找出c^d除以n的余数( m )。 从而,

2790^2753 = 65 (mod 3233)

2790^2753 = 65 (mod 3233)

That’s it! My friend decrypted my message (2790) and gets 65, which is exactly the ASCII code for ‘A’!

而已! 我的朋友解密了我的消息( 2790 ),得到65 ,这恰好是'A'的ASCII码!

The PHP program to do this process is shown below. I am using BC first and then GMP:

下面显示了执行此过程PHP程序。 我先使用BC,然后使用GMP:

<?php

$letter = 'A';

$m = ord($letter); // ASCII code of letter 'A'
$d = 2753;

$e = 17;
$n = 3233;

echo "Encryption / Decryption using BC:\n";
$c = bcmod(bcpow($m, $e, 40), $n);
$res = bcmod(bcpow($c, $d, 40), $n);

echo "Original data: $letter\n";
echo "Encrypted data: $c\n";
echo "Decryption:\n";
echo "Input: $c\n";
echo "Decrypted: $res\n";
echo "The letter is: ".chr($res)."\n";

echo "=========================\n";
echo "Encryption / Decryption using GMP:\n";
$c = gmp_powm($m, $e, $n);
$res = gmp_powm($c, $d, $n);

echo "Original data: $letter\n";
echo "Encrypted data:".gmp_strval($c)." \n";
echo "Decryption:\n";
echo "Input: ".gmp_strval($c)."\n";
echo "Decrypted: ".gmp_strval($res)."\n";
echo "The letter is: ".chr(gmp_strval($res))."\n";

The results are shown in below screen shot:

结果显示在以下屏幕截图中:

alt

BC and GMP perform equally well in this demo. The encryption and decryption are equally fast and finish instantaneously. As the RSA algorithm only involves big integers, the accuracy is well preserved.

BC和GMP在此演示中的表现均相当好。 加密和解密同样快,并且可以立即完成。 由于RSA算法仅涉及大整数,因此可以很好地保持准确性。

Something not shown here is the capability that both libraries can handle really big numbers. For example, in our decryption process, we calculated a very big number (2790^2753, which is a number of 9486 digits)!

这里未显示的是两个库都可以处理非常大的数字的功能。 例如,在解密过程中,我们计算了一个非常大的数字(2790 ^ 2753,它是9486位数字)!

The demo above, of course, can’t be really used as a serious RSA program. The length of the key (length of 3233 expressed in binary) is only 12. In actual usage, the length should be normally set to 1024 digits, or 2048 digits for particularly sensitive information.

当然,上面的演示不能真正用作严肃的RSA程序。 密钥的长度(3233的长度以二进制表示)只有12个。在实际使用中,长度通常应设置为1024位,对于特别敏感的信息,通常应设置为2048位。

结论 (Conclusion)

In this article, we reviewed the 3 libraries that provide big integer and/or arbitrary precision calculation capabilities: BC Math, GMP, php-bignumbers.

在本文中,我们回顾了3个提供大整数和/或任意精度计算功能的库:BC Math,GMP,php-bignumbers。

The author’s recommendation is to use BC Math as it supports both integers and floating numbers and it also runs pretty fast. Or, we can choose to rely on PHP’s built-in floating numbers if we only care about the first 10 digits or less.

作者的建议是使用BC Math,因为它支持整数和浮点数,并且运行速度也很快。 或者,如果我们只关心前10位或更少的数字,则可以选择依赖PHP的内置浮点数。

To conclude this article, I will display an encrypted message below using the above RSA configuration. Let me know if you can decrypt it! (The code to decrypt the below sequence is also included on Github)

总结本文,下面我将使用上面的RSA配置显示一个加密的消息。 让我知道您是否可以解密它! (解密以下序列的代码也包含在Github上)

The message goes:

消息是:

1486 1992 745 2185 2578 1313 1992 884 2185 1992 281 2185 2235 884 2412 3179 2570 2160 884 1313 1992 884 2185 1992 2680 3179 884 1313 612 2185 3179 2235 884 1853

1486 1992 745 2185 2578 1313 1992 884 2185 1992 281 2185 2235 884 2412 3179 2570 2160 884 1313 1992 884 2185 1992 2680 3179 884 1313 612 2185 3179 2235 884 1853

翻译自: https://www.sitepoint.com/arbitrary-precision-big-numbers-php/

js 大数精度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值