【问题标题】:How to compute the sine of huge numbers如何计算大数的正弦
【发布时间】:2016-07-04 21:23:41
【问题描述】:

几天来,我一直想知道如何计算幅度在100000!(弧度)左右的巨大数字的正弦值。阶乘只是一个例子,数字本身可以是任何不只是阶乘积......)我显然不使用来自 boost 多精度库的double 而是cpp_rational。但我不能简单地做100000! mod 2pi,然后使用内置函数sinl(我不需要超过10个十进制数字..),因为我需要几百万位的圆周率才能准确地做到这一点。

有什么办法可以做到吗?

【问题讨论】:

  • 这确实是一个非常困难的问题:好的数学库实际上使用大量 pi 的数字(无限 pi 近似),而其他人使用更差但更便宜的有限 pi 近似。
  • @duffymo 你没抓住重点。可以这么说,按一些天文单位计算。
  • 无法赢得所有人。也许我们应该问他为什么/如何打算计算 100000!。那只是无知。
  • 在不了解sin(x) 中的x 的情况下,您只能使用足够精确的Pi 常量。如果您对结果和/或论点有更多了解,那么您可以利用它。例如,在几何问题上,您通常可以应用 CORDIC。在代数上,您可以使用恒等式或相似性。如果只是一些子结果,有时移植到复杂域会有所帮助(以exp 形式使用欧拉公式)...帮助我们需要了解更多...

标签: c++ math boost trigonometry


【解决方案1】:

这通常是一项非常重要的任务,因为它与Discrete Logarithm Problem 有许多相似之处,这又意味着计算密集型计算。
也就是说,如果您考虑 100000!/pi 的对数,您的计算可能会更容易,因为它会减少为等于或小于 100000 的所有正整数的对数之和,并减去:log(N!/pi) = \sum_{i=0}^N (log i) - log(pi)。如果您将此数字取幂,则您的近似值为(N!/pi)。减去整数部分,然后将结果乘以pi。这是您的N! mod pi 的估计值。
公式中:

您可能注意到,我多次使用了近似这个词。这是出于以下考虑:

  • 你必须计算很多logs,这有一些成本和错误
  • 您可能希望根据问题大小更改日志的基础;这又会影响结果的准确性和精确度
  • 您必须取幂:小错误可能导致大错误
  • 减去大量数字:可能会导致大量取消
  • 乘以pi 并计算sin: 再次出现错误

如果您认为这可能有益,请考虑使用Stirling's approximation

最后要说的是,这类问题没有简单的解决方案,您总是需要逐案处理。

【讨论】:

  • 问题是:我实际上并没有计算sin(100000!),而只是有一个数字100000! 一样大,我想为它计算正弦值。跨度>
  • 好的,您可以使用logs 表示任何正数,对吧? :-)
  • 是的,当然,但我实际上不能像你描述的那样使用总和。
  • 这是真的。在这种情况下,您不需要总和。我假设您可以以某种方式表示您的大输入数字,因此您可以计算它的日志。当然你也可以减去。这里真正的重点是,如何正确地确定日志库的尺寸。
  • Base 2 在计算机编程中基本上是一个不错的选择。因为您可以使用位移来求幂,这相当快。
【解决方案2】:

注意:= pi

以弧度计算一个非常大的数字的 sin (除以 3.1415 将它们更改为  的倍数)
1. 观察:sin 0 = 0, sin 0.5pi = 1, sin pi = 1, sin1.5pi = -1, sin 2pi=0
2. pi前面的偶数或奇数整数值,sin为0
3、实数值(带小数的),小数点前的偶数取0.something作为正弦值,奇数取1.something作为正弦值。
4. 看例子 *请注意,正弦和余弦本质上是周期性的,这就是为什么可以以这种方式对大数或小数执行此操作。 :)

例如。 (使用您的计算器检查计算结果)

1.0 以弧度表示:sin 100 = -0.506
除以 3.1415
度数
sin 31.831pi(31.831为实数)= sin1.831(180) =-0.506,检查

2.0 弧度:sin 50 = -0.2623
除以 3.1415
度数
罪 15.9155pi = sin1.9155 (180) =-0.2623

3.0 弧度:sin 700 = 0.5439
除以 3.1415
度数
sin 222.8169pi = sin0.8169 (180) =-0.5440,检查

4.0 以弧度表示:sin 15000 = 0.8934
除以 3.1415
度数
sin 4774.6483pi = sin0.6483 (180) = 0.893,检查

您可以看到所有答案都通过使用弧度模式下的计算器直接计算值来检查。希望这会有所帮助。

如果你想写出一个计算程序,最好能弄清楚算法。

【讨论】:

    【解决方案3】:

    Wikipedia 列出了许多三角恒等式。有些在参数中包含产品,例如Chebyshev's Method,它是递归的,但可以使用Chebyshev Polynomials 和/或记忆化来减少递归。如果您的论点像阶乘一样容易分解,那么这可能是一种可行的方法。

    【讨论】:

      【解决方案4】:

      也许您可以使用 cpp_rational 直接从您的非常大的数字中计算窦:

      sin(x): x/1! - x^3/3! + x^5/5! - x^7/7! + ...
      

      重复此系列,直到(对于您的应用程序)没有发生重大变化。这样你就可以完全避免数字 pi。

      【讨论】:

      • x=0 处的泰勒级数展开只是正弦前几个周期的近似值,否则我必须循环总和数千次,这是不切实际的(不能使用 x=very big 的扩展,因为我需要计算正弦...)
      • 如您所见,sin Taylor 扩展在其符号中交替出现。所以你最终总结了许多条款,并取消了一些。这可能会降低准确性,从而获得稳定的结果,但这是错误的。还要考虑到您需要评估一个已经非常大的数字的功效,这个数字越来越差。
      • @fedino 使用任意精度的有理数,这不会发生。
      • @OliverBorchert 用序列表示计算一个数量级的结果需要多长时间?
      • @BaummitAugen 你将无法完成.. 100000! ^ 100 已经非常耗时,您需要指数为 100000 的多项式! / 3 大约这肯定是不可能的
      猜你喜欢
      • 2016-06-16
      • 1970-01-01
      • 2014-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-19
      相关资源
      最近更新 更多