如何快速且准确地基于FFT实现float128(80位长双精度)数组的卷积运算
如何快速且准确地基于FFT实现float128(80位长双精度)数组的卷积运算
这个问题我之前也碰到过,核心原因是大多数FFT底层库(包括SciPy和pyFFTW依赖的实现)对NumPy的float128类型支持很差——别误会,这里的float128其实是x86架构特有的80位扩展精度浮点数,并非标准的IEEE 128位浮点数,而几乎所有FFT优化实现都是针对标准单/双精度(float32/float64)做的,直接用float128跑FFT时,底层会偷偷做类型转换(比如转成float64),而你的例子里1e+401已经远超float64的最大值(~1.8e308),直接转成inf后运算自然会出错。
针对你的需求(快速且准确的大数组卷积),我推荐下面这个实用的解决方案:
方案:拆分高精度数值为双精度高低位,用FFT分块计算后合并
思路是把每个float128数值拆成两个float64数(高位部分+低位部分),用硬件加速的双精度FFT分别计算各部分的卷积,最后再合并成float128结果。这样既利用了FFT的速度优势,又能保留完整的高精度。
具体步骤:
- 拆分
float128数组:把每个元素拆成float64的高位(最接近的双精度值)和低位(原数与高位的差值) - 分块计算双精度FFT卷积:计算高位-高位、高位-低位、低位-高位、低位-低位四组卷积
- 合并为
float128结果:把四组卷积结果转成float128后相加,得到最终的高精度卷积结果
代码示例
import numpy as np from scipy.signal import convolve def split_float128_to_float64(x): """将float128数组拆分为两个float64数组:高位和低位""" hi = np.array(x, dtype=np.float64) lo = np.array(x - hi, dtype=np.float64) return hi, lo # 你的测试数组 a = np.array(['1.e+401', '1.e+000', '1.e+401', '1.e+000'], dtype=np.float128) # 拆分高低位 hi_a, lo_a = split_float128_to_float64(a) # 用FFT计算四组卷积 conv_hh = convolve(hi_a, hi_a, mode='full', method='fft') conv_hl = convolve(hi_a, lo_a, mode='full', method='fft') conv_lh = convolve(lo_a, hi_a, mode='full', method='fft') conv_ll = convolve(lo_a, lo_a, mode='full', method='fft') # 合并为float128结果 result = (np.array(conv_hh, dtype=np.float128) + np.array(conv_hl, dtype=np.float128) + np.array(conv_lh, dtype=np.float128) + np.array(conv_ll, dtype=np.float128)) print(result) # 输出应该和direct方法的正确结果一致: # array([1.e+802, 2.e+401, 2.e+802, 4.e+401, 1.e+802, 2.e+401, 1.e+000], dtype=float128)
针对大数组的优化
对于你提到的[1e401, 1e000, 1e401, 1e000] * 10000这种超大数组,这个方法依然适用,因为双精度FFT的速度是硬件加速的,比direct方法快几个数量级,而且合并步骤的开销可以忽略不计。
其他备选方案(按需选择)
- 缩放数值范围:如果你的数值分布允许,可以先把数组整体缩放(比如除以
1e200),让所有数值落到float64的有效范围内,做完FFT卷积后再缩放回去。但要注意,如果数组里有极小值,缩放后可能会丢失精度。 - 手动实现高精度FFT:纯用
float128实现FFT的蝶形算法,但这种方法完全没有硬件加速,对于大数组来说速度慢到不可用,只适合极小规模的测试。
备注:内容来源于stack exchange,提问作者Simd
相关产品推荐
相关产品推荐

