12

是否可以安全地从双数组存储到浮点数组?

4

5 回答 5

32

取决于你想要什么。这些值肯定不会被保留。如果需要,请使用std::copy.

#include <algorithm>

int main()
{
    double a[] = {1.618, 3.1416, 2.7, 0.707, 1.0};
    float b[5];
    std::copy(a, a + 5, b);
}
于 2010-06-02T15:19:15.420 回答
4

问题是不能保证编译器对 a 的二进制表示是 adouble的等价表示float。为了memcpy用于多字节类型,底层表示必须相同(相同的布局)。您可以安全地复制floatfloatintintdoubledouble

当源类型与目标类型不匹配时,您注定会出现未定义的行为long,例如从tocharfloatto复制double。该memcpy功能不进行任何转换或执行任何促销活动。它只是复制。

于 2010-06-02T16:41:20.017 回答
2

就像许多其他人回答的那样,使用memcpy不起作用,因为这两种类型(通常)大小不同。请在http://en.cppreference.com/w/cpp/language/types查看更多信息,或者更具体地说:

浮点类型

float - 单精度浮点类型。通常为 IEEE-754 32 位浮点型

double - 双精度浮点类型。通常为 IEEE-754 64 位浮点型

long double - 扩展精度浮点类型。不一定映射到 IEEE-754 规定的类型。通常是 x86 和 x86-64 架构上的 80 位 x87 浮点类型。

Usingstd::copy会给你一个编译器警告(至少对我来说是在 VS2015/VS2017 编译器上),因为编译器不允许通过 std::copy 从 double 到 float 隐式损失精度,而不会警告开发人员。如果你treat warnings as errors设置了标志,你会得到一个编译器错误。

1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2316): error C2220: warning treated as error - no 'object' file generated
1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2335): note: see reference to function template instantiation '_OutIt std::_Copy_unchecked1<_InIt,_OutIt>(_InIt,_InIt,_OutIt,std::_General_ptr_iterator_tag)' being compiled
1>        with
1>        [
1>            _OutIt=float *,
1>            _InIt=double *
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2354): note: see reference to function template instantiation '_OutIt *std::_Copy_unchecked<_InIt,float*>(_InIt,_InIt,_OutIt)' being compiled
1>        with
1>        [
1>            _OutIt=float *,
1>            _InIt=double *
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2364): note: see reference to function template instantiation '_OutIt std::_Copy_no_deprecate1<double*,_OutIt>(_InIt,_InIt,_OutIt,std::random_access_iterator_tag,std::random_access_iterator_tag)' being compiled
1>        with
1>        [
1>            _OutIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
1>            _InIt=double *
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2373): note: see reference to function template instantiation '_OutIt std::_Copy_no_deprecate<_InIt,_OutIt>(_InIt,_InIt,_OutIt)' being compiled
1>        with
1>        [
1>            _OutIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
1>            _InIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>
1>        ]
1>test.cpp(153): note: see reference to function template instantiation '_OutIt std::copy<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>,std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>>(_InIt,_InIt,_OutIt)' being compiled
1>        with
1>        [
1>            _OutIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
1>            _InIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\xutility(2316): warning C4244: '=': conversion from 'double' to 'float', possible loss of data

相反,我建议使用该std::transform功能,并结合执行特定演员的 lamda。这也更清楚地表明实际上正在发生显式的精度损失。

std::vector<double> doubles = { 5.0, 10.0, 242.130, 42.0 };
std::vector<float> floats(doubles.size());
std::transform(std::begin(doubles), std::end(doubles), std::begin(floats), [&](const double& value) { return static_cast<float>(value); });
于 2018-05-31T08:30:56.147 回答
1

在一般情况下 - 不。

在特定情况下,在给定平台上,float和的表示double可能相同,并且复制将成功。但无论如何它没有任何实际意义。

于 2010-06-02T16:52:10.617 回答
1

memcpy是类型不可知的(只看到字节)并且不能进行类型转换。就像std::transform@AzP 所说的那样使用:

std::transform(a, a + 5, b, [](double d) -> float {return float(d);});
于 2018-12-18T22:07:54.307 回答