复数计算误差随着矩阵大小的增加而增加
Complex number computational error grows as the size of matrix increase
如果我有两个小的复数矩阵,即使我手动执行复数乘法也很好(将复数分解为实部和虚部并分别进行乘法)。
import numpy as np
a_shape = (3,10)
b_shape = (10,3)
# Generating the first complex matrix a
np.random.seed(0)
a_real = np.random.randn(a_shape[0], a_shape[1])
np.random.seed(1)
a_imag = np.random.randn(a_shape[0], a_shape[1])
a = a_real + a_imag*1j
# Generating the second complex matrix b
np.random.seed(2)
b_real = np.random.randn(b_shape[0], b_shape[1])
np.random.seed(3)
b_imag = np.random.randn(b_shape[0], b_shape[1])
b = b_real + b_imag*1j
# 1st approach to do complex multiplication
output1 = np.dot(a,b)
# Manaul complex multiplication
output_real = np.dot(a.real,b.real) - np.dot(a.imag,b.imag)
np.array_equal(output1.real, output_real) # the results are the same
>>> True
但是如果我的矩阵比较大,np.(a,b)
和手动相乘得到的结果是不一样的
a_shape = (3,500)
b_shape = (500,3)
# Generating the first complex matrix a
np.random.seed(0)
a_real = np.random.randn(a_shape[0], a_shape[1])
np.random.seed(1)
a_imag = np.random.randn(a_shape[0], a_shape[1])
a = a_real + a_imag*1j
# Generating the second complex matrix b
np.random.seed(2)
b_real = np.random.randn(b_shape[0], b_shape[1])
np.random.seed(3)
b_imag = np.random.randn(b_shape[0], b_shape[1])
b = b_real + b_imag*1j
# 1st approach to do complex multiplication
output1 = np.dot(a,b)
# 2nd approach to do complex multiplication
output_real = np.dot(a.real,b.real) - np.dot(a.imag,b.imag)
np.array_equal(output1.real, output_real)
>>> False
我问这个是因为我需要在 pytorch
中做一些复数乘法。 pytorch
本身不支持复数,所以我需要为真实和图像组件手动完成。
然后结果比使用 np.dot(a,b)
略有偏差
这个问题有什么解决办法吗?
两次计算的差异
output1.real - output_real
>>>array([[-3.55271368e-15, -2.48689958e-14, 1.06581410e-14],
[-1.06581410e-14, -5.32907052e-15, -7.10542736e-15],
[ 0.00000000e+00, -2.84217094e-14, -7.10542736e-15]])
你没有说差异有多小,但我怀疑你所看到的与复数无关,而是与浮点运算的性质有关。
特别是浮点加法是不结合的,也就是说我们不一定有
(a + b) + c = a + (b + c)
这将解释您所看到的,因为您正在做的是比较
Sum{ Ra[i]*Rb[i] - Ia[i]*Ib[i]}
和
Sum{ Ra[i]*Rb[i]} - Sum{ Ia[i]*Ib[i]}
(其中 Ra[i] 是 a[i] 等的实部)
要证明这是问题所在,有一件事是将数字的实部和复数部分限制为十六分之一的整数。有了这样的数字——只要你不添加一个离谱的数字(许多数十亿)——双精度浮点运算将是精确的,所以你应该得到相同的结果。例如,在 C 语言中,您可以通过生成一堆介于 -16 和 16 之间的随机整数,然后将每个整数除以(双精度)数字 16.0 来生成此类数字,以获得 -1 和 1 之间的双精度数字,这是一个整体十六分之一的数目。
如果我有两个小的复数矩阵,即使我手动执行复数乘法也很好(将复数分解为实部和虚部并分别进行乘法)。
import numpy as np
a_shape = (3,10)
b_shape = (10,3)
# Generating the first complex matrix a
np.random.seed(0)
a_real = np.random.randn(a_shape[0], a_shape[1])
np.random.seed(1)
a_imag = np.random.randn(a_shape[0], a_shape[1])
a = a_real + a_imag*1j
# Generating the second complex matrix b
np.random.seed(2)
b_real = np.random.randn(b_shape[0], b_shape[1])
np.random.seed(3)
b_imag = np.random.randn(b_shape[0], b_shape[1])
b = b_real + b_imag*1j
# 1st approach to do complex multiplication
output1 = np.dot(a,b)
# Manaul complex multiplication
output_real = np.dot(a.real,b.real) - np.dot(a.imag,b.imag)
np.array_equal(output1.real, output_real) # the results are the same
>>> True
但是如果我的矩阵比较大,np.(a,b)
和手动相乘得到的结果是不一样的
a_shape = (3,500)
b_shape = (500,3)
# Generating the first complex matrix a
np.random.seed(0)
a_real = np.random.randn(a_shape[0], a_shape[1])
np.random.seed(1)
a_imag = np.random.randn(a_shape[0], a_shape[1])
a = a_real + a_imag*1j
# Generating the second complex matrix b
np.random.seed(2)
b_real = np.random.randn(b_shape[0], b_shape[1])
np.random.seed(3)
b_imag = np.random.randn(b_shape[0], b_shape[1])
b = b_real + b_imag*1j
# 1st approach to do complex multiplication
output1 = np.dot(a,b)
# 2nd approach to do complex multiplication
output_real = np.dot(a.real,b.real) - np.dot(a.imag,b.imag)
np.array_equal(output1.real, output_real)
>>> False
我问这个是因为我需要在 pytorch
中做一些复数乘法。 pytorch
本身不支持复数,所以我需要为真实和图像组件手动完成。
然后结果比使用 np.dot(a,b)
略有偏差
这个问题有什么解决办法吗?
两次计算的差异
output1.real - output_real
>>>array([[-3.55271368e-15, -2.48689958e-14, 1.06581410e-14],
[-1.06581410e-14, -5.32907052e-15, -7.10542736e-15],
[ 0.00000000e+00, -2.84217094e-14, -7.10542736e-15]])
你没有说差异有多小,但我怀疑你所看到的与复数无关,而是与浮点运算的性质有关。
特别是浮点加法是不结合的,也就是说我们不一定有
(a + b) + c = a + (b + c)
这将解释您所看到的,因为您正在做的是比较
Sum{ Ra[i]*Rb[i] - Ia[i]*Ib[i]}
和
Sum{ Ra[i]*Rb[i]} - Sum{ Ia[i]*Ib[i]}
(其中 Ra[i] 是 a[i] 等的实部)
要证明这是问题所在,有一件事是将数字的实部和复数部分限制为十六分之一的整数。有了这样的数字——只要你不添加一个离谱的数字(许多数十亿)——双精度浮点运算将是精确的,所以你应该得到相同的结果。例如,在 C 语言中,您可以通过生成一堆介于 -16 和 16 之间的随机整数,然后将每个整数除以(双精度)数字 16.0 来生成此类数字,以获得 -1 和 1 之间的双精度数字,这是一个整体十六分之一的数目。