C++ std::vector 乘法中是不是存在已知的不一致行为?

Posted

技术标签:

【中文标题】C++ std::vector 乘法中是不是存在已知的不一致行为?【英文标题】:Is there a known inconsistent behavior in C++ std::vector multiplication?C++ std::vector 乘法中是否存在已知的不一致行为? 【发布时间】:2017-04-11 17:00:01 【问题描述】:

我正在将 Python 代码翻译成 C++。

我在下面的 sn-p 中遇到问题。这两个代码应该是同一个东西,但是它们给了我不同的输出。

我迷路了。错误从k=1 开始。发生了什么,错误在哪里?

如果这很重要:我正在使用 IDE Eclipse Parallel Mars、Windows 10、MinGW 编译 C++ 代码。

Python 3.5:

import numpy as np
a = np.array(([2,-1,0,0],[-1,1.5,-0.5,0],[0,-0.5,0.75,-0.25],[0,0,-0.25,0.25]))
b = np.array(([0,0,0,1]))
for k in range(len(b)-1,-1,-1):
    p = 0
    print("")
    print("k = ", k)
    print("b[k] = ", b[k])
    for m in range(k+1, len(b)):
        print("m = ", m)
        print("b[m] = ", b[m])
        print("a[k,m] = ",a[k,m])
        p += a[k,m] * b[m];
        print("p = ", p)

    b[k] = (b[k] - p)/a[k,k];

C++11:

#include <iostream>
#include <vector>

int main()
    std::vector< std::vector<double> > a =  2,-1,0,0, -1,1.5,-0.5,0,
                0,-0.5,0.75,-0.25, 0,0,-0.25,0.25 ;
    std::vector<double> b = 0,0,0,1;
    double p;
    for (int k = b.size()-1; k >= 0; --k) 
        p = 0;
        std::cout << std::endl << "k = " << k << std::endl;
        std::cout << "b[k] = " << b[k] << std::endl;
        for (size_t m = k+1; m < b.size(); ++m) 
            std::cout << "m = " << m << std::endl;
            std::cout << "b[m] = " << b[m] << std::endl;
            std::cout << "a[k][m] = " << a[k][m] << std::endl;
            p += a[k][m] * b[m];
            std::cout << "p = " << p << std::endl;
        
        b[k] = (b[k] - p)/a[k][k];
    
    return 0;


输出

Python 3.5:

k =  3
b[k] =  1

k =  2
b[k] =  0
m =  3
b[m] =  4
a[k,m] =  -0.25
p =  -1.0

k =  1
b[k] =  0
m =  2
b[m] =  1
a[k,m] =  -0.5
p =  -0.5
m =  3
b[m] =  4
a[k,m] =  0.0
p =  -0.5

k =  0
b[k] =  0
m =  1
b[m] =  0
a[k,m] =  -1.0
p =  0.0
m =  2
b[m] =  1
a[k,m] =  0.0
p =  0.0
m =  3
b[m] =  4
a[k,m] =  0.0
p =  0.0

C++11:

k = 3
b[k] = 1

k = 2
b[k] = 0
m = 3
b[m] = 4
a[k][m] = -0.25
p = -1

k = 1
b[k] = 0
m = 2
b[m] = 1.33333
a[k][m] = -0.5
p = -0.666667
m = 3
b[m] = 4
a[k][m] = 0
p = -0.666667

k = 0
b[k] = 0
m = 1
b[m] = 0.444444
a[k][m] = -1
p = -0.444444
m = 2
b[m] = 1.33333
a[k][m] = 0
p = -0.444444
m = 3
b[m] = 4
a[k][m] = 0
p = -0.444444

【问题讨论】:

在您的 Python 中,b 具有整数 dtype 而不是浮点数。 旁注:reversed(range(0, len(b)) 的效率并没有降低,而且似乎更具可读性。 @cdhowie 不在 Python 3+ 中,(b[k] - p)/a[k,k] 将是浮点数。然而,一旦分配给b[k],它就会被转换为一个整数,正如 user235711 所暗示的那样。 【参考方案1】:

您的 Python 代码有缺陷。它会截断数字,从而产生整数值,而您期望浮点数带有小数部分。

特别是,np.array(([0,0,0,1])) 正在创建一个具有整数数据类型的 numpy 数组,这意味着当您分配给b[k] 时,浮点值将被截断为整数。从the docs 到numpy.array(),关于可选的dtype 参数(强调我的):

数组所需的数据类型。如果没有给出,则类型将被确定为在序列中保存对象所需的最小类型。

由于您在输入数组中只提供了整数值,numpy 推断您想要创建一个整数数组。

C++ 代码是正确的。

当我修复您的 Python 代码以在任何地方使用浮点值时,输出与 C++ 版本匹配:

import numpy as np
a = np.array(([2.0,-1.0,0.0,0.0],[-1.0,1.5,-0.5,0.0],[0.0,-0.5,0.75,-0.25],[0.0,0.0,-0.25,0.25]))
b = np.array(([0.0,0.0,0.0,1.0]))
for k in range(len(b)-1,-1,-1):
    p = 0
    print("")
    print("k = ", k)
    print("b[k] = ", b[k])
    for m in range(k+1, len(b)):
        print("m = ", m)
        print("b[m] = ", b[m])
        print("a[k,m] = ",a[k,m])
        p += a[k,m] * b[m];
        print("p = ", p)

    b[k] = (b[k] - p)/a[k,k];

【讨论】:

【参考方案2】:

如果您在创建数组时将dtype 指定为'float64' b

b = np.array(([0,0,0,1]), dtype='float64')

输出如下,与您的 C++ 程序相匹配:

k = 3
b[k] = 1.0

k = 2
b[k] = 0.0
m = 3
b[m] = 4.0
a[k,m] = -0.25
p = -1.0

k = 1
b[k] = 0.0
m = 2
b[m] = 1.3333333333333333
a[k,m] = -0.5
p = -0.66666666666666663
m = 3
b[m] = 4.0
a[k,m] = 0.0
p = -0.66666666666666663

k = 0
b[k] = 0.0
m = 1
b[m] = 0.44444444444444442
a[k,m] = -1.0
p = -0.44444444444444442
m = 2
b[m] = 1.3333333333333333
a[k,m] = 0.0
p = -0.44444444444444442
m = 3
b[m] = 4.0
a[k,m] = 0.0
p = -0.44444444444444442

【讨论】:

以上是关于C++ std::vector 乘法中是不是存在已知的不一致行为?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中检查 std::vector<string> 是不是包含某个值 [重复]

使用 std::vector::swap 方法在 C++ 中交换两个不同的向量是不是安全?

C++ std::vector count统计某个元素个数 是否存在某个值

std::vector 不是 push_back 值到我的向量中吗? C++

在 C++ 中使用 std::vector<bool> 对象是不是可以接受,还是应该使用替代方法?

C++,2D std::vector,我是不是需要明确保留和推回空向量?