搜索
首页web前端js教程使用快速傅里叶变换 (FFT) 乘以大十进制数

Multiplying Large Decimal Numbers Using Fast Fourier Transform (FFT)

介绍

将大十进制数相乘可能在计算上具有挑战性,尤其是在处理具有许多位数或多个小数位的数字时。传统的乘法方法对于极大的数字来说效率很低。这就是快速傅里叶变换 (FFT) 发挥作用的地方,它提供了一种强大而高效的算法,可以以惊人的速度进行大数相乘。

乘法中的应用

  • FFT 通过将数字变换到频域、执行逐点乘法,然后应用逆 FFT 来实现多项式或大整数的快速乘法。

大数乘法的挑战

传统乘法方法的时间复杂度为 O(n²),其中 n 是位数。对于非常大的数字,这在计算上变得昂贵。基于 FFT 的乘法算法将这种复杂性降低到 O(n log n),使得处理大数的速度显着加快。

Cooley-Tukey FFT 的证明大纲

  1. 离散傅立叶变换 (DFT) 的分解:

    • DFT 定义为:
      Xk=Σn=0N1 xne2π ikn/N,X_k = sum_{n=0}^{N-1} x_n cdot e^{-2pi i cdot kn / N}, Xk = n=0ΣN−1 xne−2πi⋅kn /N,
      在哪里 NN N 是输入信号的大小。
    • Cooley-Tukey FFT 将计算分解为更小的 DFT N/2N/2 N/2 通过分离偶数索引和奇数索引项:
      Xk=Σn=0N/2 1x2ne2πi (2n )k/N Σn=0N / 21x2 n 1e2 πi(2n 1)k/NX_k = sum_{n=0}^{N/2-1} x_{2n} cdot e^{-2pi i cdot (2n)k / N} sum_{n=0}^{N/2-1} x_{2n 1} cdot e^{-2pi i cdot (2n 1)k / N}。 Xk = n=0ΣN/2−1x2n e −2πi⋅(2n)k/N n=0ΣN/ 2−1x2n 1e−2πi⋅(2n 1)k/N.
    • 这减少为:
      Xk=偶数项的 DFT Wk奇数项的 DFT, X_k = text{偶数项的DFT} W_k cdot text{奇数项的DFT}, Xk =偶数项的 DFT Wk奇数项的 DFT,
      在哪里 Wk=e2πik/N W_k = e^{-2pi i cdot k / N} Wk =e−2πi ⋅k/N .
  2. 递归结构:

    • 每个大小的 DFT NN N 被分成两个大小的 DFT N/2N/2 N/2 ,导致递归结构。
    • 这种递归除法一直持续到大小的基本情况 N=1N = 1 N=1 ,此时 DFT 只是输入值。
  3. 蝴蝶操作:

    • 该算法使用蝶形运算合并较小 DFT 的结果:
      a=u Wkv ,b=uWkv,a' = u W_k cdot v,四边形 b' = u - W_k cdot v, 一个=u Wkv,b =u−Wkv,
      在哪里 uu u vv v 是较小 DFT 的结果, WkW_k Wk 代表团结的根源。
  4. 位反转排列:

    • 输入数组根据索引的二进制表示重新排序,以实现就地计算。
  5. 时间复杂度:

    • 在每一层递归中,都有 NN N 涉及单位根的计算,递归的深度是 日志2(N)log_2(N) log2 (N) .
    • 这会产生时间复杂度 O(N logNO(N log N) O(NlogN) .

逆FFT

  • 逆 FFT 类似,但使用 e2πi kn/Ne^{2pi i cdot kn / N} e 2πi⋅kn/N 作为基础并对结果进行缩放 1/N1/N 1/N .

了解 FFT 乘法算法

FFT 乘法算法的工作原理有几个关键步骤:

  1. 预处理数字

    • 将输入数字转换为数字数组
    • 同时处理整数和小数部分
    • 将数组填充到最接近的 2 次幂以进行 FFT 计算
  2. 快速傅立叶变换

    • 使用 FFT 将数字数组转换为频域
    • 这将乘法问题转化为频域中更简单的逐点乘法
  3. 频域乘法

    • 对转换后的数组执行逐元素乘法
    • 利用复数运算进行高效计算
  4. 逆FFT和结果处理

    • 将相乘后的数组变换回时域
    • 处理数字进位
    • 重构最终的十进制数

实施的关键组成部分

复数表示

class Complex {
  constructor(re = 0, im = 0) {
    this.re = re;  // Real part
    this.im = im;  // Imaginary part
  }

  // Static methods for complex number operations
  static add(a, b) { /* ... */ }
  static subtract(a, b) { /* ... */ }
  static multiply(a, b) { /* ... */ }
}

Complex 类对于执行 FFT 运算至关重要,它使我们能够操作实域和虚域中的数字。

快速傅立叶变换函数

function fft(a, invert = false) {
  // Bit reversal preprocessing
  // Butterfly operations in frequency domain
  // Optional inverse transformation
}

FFT函数是算法的核心,有效地在时域和频域之间进行数字转换。

处理小数

该实现包括处理十进制数的复杂逻辑:

  • 分隔整数和小数部分
  • 跟踪小数点总数
  • 使用正确的小数点位置重建结果

示例用例

// Multiplying large integers
fftMultiply("12345678901234567890", "98765432109876543210")

// Multiplying very large different size integers
fftMultiply("12345678901234567890786238746872364872364987293795843790587345", "9876543210987654321087634875782369487239874023894")

// Multiplying decimal numbers
fftMultiply("123.456", "987.654")

// Handling different decimal places
fftMultiply("1.23", "45.6789")

// Handling different decimal places with large numbers
fftMultiply("1234567890123456789078623874687236487236498.7293795843790587345", "98765432109876543210876348757823694.87239874023894")

性能优势

  • 时间复杂度:O(n log n) 与传统方法的 O(n²) 相比
  • 精度:处理具有多个小数位的极大数字
  • 效率:大量乘法运算速度明显加快

限制和注意事项

  • 需要额外的内存来表示复数
  • 浮点运算会影响精度
  • 与传统乘法相比,实现更复杂

结论

FFT 乘法算法代表了一种有效地乘以大数的强大方法。通过利用频域变换,我们可以以惊人的速度和精度执行复杂的数学运算。

实际应用

  • 科学计算
  • 财务计算
  • 密码学
  • 大规模数值模拟

进一步阅读

  • Cooley-Tukey FFT 算法
  • 数论
  • 计算数学

代码

完整的实现如下,为使用快速傅里叶变换方法乘以大十进制数提供了一个强大的解决方案。

/**
 * Fast Fourier Transform (FFT) implementation for decimal multiplication
 * @param {number[]} a - Input array of real numbers
 * @param {boolean} invert - Whether to perform inverse FFT
 * @returns {Complex[]} - Transformed array of complex numbers
 */
class Complex {
  constructor(re = 0, im = 0) {
    this.re = re;
    this.im = im;
  }

  static add(a, b) {
    return new Complex(a.re + b.re, a.im + b.im);
  }

  static subtract(a, b) {
    return new Complex(a.re - b.re, a.im - b.im);
  }

  static multiply(a, b) {
    return new Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re);
  }
}

function fft(a, invert = false) {
  let n = 1;
  while (n > 1;
    for (; j & bit; bit >>= 1) {
      j ^= bit;
    }
    j ^= bit;
    if (i > 1;
    for (let i = 0; i  {
    const [intPart, decPart] = numStr.split(".");
    return {
      intPart: intPart || "0",
      decPart: decPart || "",
      totalDecimalPlaces: (decPart || "").length,
    };
  };

  const parsed1 = parseNumber(num1);
  const parsed2 = parseNumber(num2);

  // Combine numbers removing decimal point
  const combinedNum1 = parsed1.intPart + parsed1.decPart;
  const combinedNum2 = parsed2.intPart + parsed2.decPart;

  // Total decimal places
  const totalDecimalPlaces =
    parsed1.totalDecimalPlaces + parsed2.totalDecimalPlaces;

  // Convert to digit arrays (least significant first)
  const a = combinedNum1.split("").map(Number).reverse();
  const b = combinedNum2.split("").map(Number).reverse();

  // Determine result size and pad
  const resultSize = a.length + b.length;
  const fftSize = 1  new Complex(x, 0));
  const complexB = b.map((x) => new Complex(x, 0));

  // Perform FFT
  const fftA = fft(complexA);
  const fftB = fft(complexB);

  // Pointwise multiplication in frequency domain
  const fftProduct = new Array(fftSize);
  for (let i = 0; i = 10) {
      result[i + 1] += Math.floor(result[i] / 10);
      result[i] %= 10;
    }
  }

  // Remove leading zeros and convert to string
  while (result.length > 1 && result[result.length - 1] === 0) {
    result.pop();
  }

  // Insert decimal point
  const resultStr = result.reverse().join("");
  if (totalDecimalPlaces === 0) {
    return resultStr;
  }

  // Handle case where result might be shorter than decimal places
  if (resultStr.length 



<h3>
  
  
  输出
</h3>



<pre class="brush:php;toolbar:false">// Example Usage - Self verify using Python
console.log(
  "Product of integers:",
  fftMultiply("12345678901234567890", "98765432109876543210")
);
console.log("Product of decimals:", fftMultiply("123.456", "987.654"));
console.log("Product of mixed decimals:", fftMultiply("12.34", "56.78"));
console.log(
  "Product with different decimal places:",
  fftMultiply("1.23", "45.6789")
);
console.log(
  "Product with large integers:",
  fftMultiply(
    "12345678901234567890786238746872364872364987293795843790587345",
    "9876543210987654321087634875782369487239874023894"
  )
);
const num1 = "1234567890123456789078623874687236487236498.7293795843790587345";
const num2 = "98765432109876543210876348757823694.87239874023894";
console.log("Product:", fftMultiply(num1, num2));
Product of integers: 1219326311370217952237463801111263526900
Product of decimals: 121931.812224
Product of mixed decimals: 700.6652
Product with different decimal places: 56.185047
Product with large integers: 121932631137021795232593613105722759976860134207381319681901040774443113318245930967231822167723255326824021430
Product: 121932631137021795232593613105722759976860134207381319681901040774443113318245.93096723182216772325532682402143

以上是使用快速傅里叶变换 (FFT) 乘以大十进制数的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript数据类型:浏览器和nodejs之间是否有区别?JavaScript数据类型:浏览器和nodejs之间是否有区别?May 14, 2025 am 12:15 AM

JavaScript核心数据类型在浏览器和Node.js中一致,但处理方式和额外类型有所不同。1)全局对象在浏览器中为window,在Node.js中为global。2)Node.js独有Buffer对象,用于处理二进制数据。3)性能和时间处理在两者间也有差异,需根据环境调整代码。

JavaScript评论:使用//和 / * * / * / * /JavaScript评论:使用//和 / * * / * / * /May 13, 2025 pm 03:49 PM

JavaScriptusestwotypesofcomments:single-line(//)andmulti-line(//).1)Use//forquicknotesorsingle-lineexplanations.2)Use//forlongerexplanationsorcommentingoutblocksofcode.Commentsshouldexplainthe'why',notthe'what',andbeplacedabovetherelevantcodeforclari

Python vs. JavaScript:开发人员的比较分析Python vs. JavaScript:开发人员的比较分析May 09, 2025 am 12:22 AM

Python和JavaScript的主要区别在于类型系统和应用场景。1.Python使用动态类型,适合科学计算和数据分析。2.JavaScript采用弱类型,广泛用于前端和全栈开发。两者在异步编程和性能优化上各有优势,选择时应根据项目需求决定。

Python vs. JavaScript:选择合适的工具Python vs. JavaScript:选择合适的工具May 08, 2025 am 12:10 AM

选择Python还是JavaScript取决于项目类型:1)数据科学和自动化任务选择Python;2)前端和全栈开发选择JavaScript。Python因其在数据处理和自动化方面的强大库而备受青睐,而JavaScript则因其在网页交互和全栈开发中的优势而不可或缺。

Python和JavaScript:了解每个的优势Python和JavaScript:了解每个的优势May 06, 2025 am 12:15 AM

Python和JavaScript各有优势,选择取决于项目需求和个人偏好。1.Python易学,语法简洁,适用于数据科学和后端开发,但执行速度较慢。2.JavaScript在前端开发中无处不在,异步编程能力强,Node.js使其适用于全栈开发,但语法可能复杂且易出错。

JavaScript的核心:它是在C还是C上构建的?JavaScript的核心:它是在C还是C上构建的?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc; saninterpretedlanguagethatrunsonenginesoftenwritteninc.1)javascriptwasdesignedAsalightweight,解释edganguageforwebbrowsers.2)Enginesevolvedfromsimpleterterterpretpreterterterpretertestojitcompilerers,典型地提示。

JavaScript应用程序:从前端到后端JavaScript应用程序:从前端到后端May 04, 2025 am 12:12 AM

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中