是否可以安全地从双数组到浮点数组进行memcpy?
答案 0 :(得分:31)
取决于你想要什么。这些价值肯定不会被保留。如果需要,请使用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);
}
答案 1 :(得分:4)
问题在于无法保证编译器的double
的二进制表示是float
的等效表示。为了使用memcpy
多字节类型,底层表示必须相同(相同的布局)。您可以安全地将float
复制到float
,将int
复制到int
,将double
复制到double
。
当源类型与目标类型不匹配时,您将注定未定义的行为,例如从long
复制到char
或float
到{ {1}}。 double
功能不会进行任何转化或执行任何促销活动。它只是复制。
答案 2 :(得分: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浮点类型。
使用std::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); });
答案 3 :(得分:1)
一般情况下 - 没有。
在特定情况下,在给定平台上,float
和double
的表示可能相同,副本也会成功。但无论如何它都没有任何实际意义。
答案 4 :(得分:1)
memcpy
是类型无关的(仅能看到字节),并且不能进行类型转换。就像@AzP所说的那样使用std::transform
:
std::transform(a, a + 5, b, [](double d) -> float {return float(d);});