C++ memcpy 从双精度数组到浮点数组

发布于 2024-09-03 21:27:40 字数 34 浏览 10 评论 0原文

是否可以安全地从双精度数组 memcpy 到浮点数组?

Is is possible to memcpy from a double array to a float array safely?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

乙白 2024-09-10 21:27:40

取决于你想要什么。这些值肯定不会被保留。如果您需要它,请使用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);
}

Depends on what you want. The values certainly won't be preserved. If you need that, use 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);
}
ゃ懵逼小萝莉 2024-09-10 21:27:40

问题在于,无法保证编译器的 double 二进制表示与 float 的等效表示。为了将memcpy用于多字节类型,底层表示必须相同(相同的布局)。您可以安全地将 float 复制到 float、将 int 复制到 int 以及将 double 复制到 <代码>双。

当源类型与目标类型不匹配时,您注定会遇到未定义的行为,例如从long复制到charfloatdoublememcpy 函数不会进行任何转换或执行任何提升。它只是复制。

The problem is that there is no guarantee that the compiler's binary representation of a double is the equivalent representation of a float. In order to use memcpy for multi-byte types is that the underlying representation must be the same (same layout). You can safely copy float to float, int to int and double to double.

You are destined for undefined behavior when the source type does not match the destination type, such as copying from long to char or float to double. The memcpy function does not make any conversion or perform any promotions. It just copies.

不喜欢何必死缠烂打 2024-09-10 21:27:40

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

浮点类型

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 隐式精度损失,而不警告开发人员。如果您设置了将警告视为错误标志,您将收到编译器错误。

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); });

Like many others have answered, using memcpy does not work since the two types are (generally) different in size. Please see more at http://en.cppreference.com/w/cpp/language/types, or more specifically:

Floating point types

float - single precision floating point type.
Usually IEEE-754 32 bit floating point type

double - double precision floating point type. Usually IEEE-754 64 bit floating point type

long double - extended precision floating point type. Does not necessarily map to types mandated by IEEE-754. Usually 80-bit x87 floating point type on x86 and x86-64 architectures.

Using std::copy will give you a compiler warning (at least for me on the VS2015/VS2017 compiler) since the compiler does not allow the implicit loss of precision from double to float via std::copy, without warning the developer about it. And if you have the treat warnings as errors flag set, you will get a compiler error.

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

Instead, I recommend using use the std::transform function, combined with a lamda performing the specific cast. This also clearer shows that an explicit loss-of-precision is actually taking place.

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); });
知足的幸福 2024-09-10 21:27:40

一般情况下 - 不。

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

In general case - no.

In specific cases, on a given platform the representation of float and double might be the same, and the copy will succeed. But it doesn't make any practical sense anyway.

夜司空 2024-09-10 21:27:40

memcpy 与类型无关(只看到字节)并且无法进行类型转换。只需使用 std::transform 正如 @AzP 所说:

std::transform(a, a + 5, b, [](double d) -> float {return float(d);});

memcpy is type agnostic (just sees bytes) and can't do type conversion. Just use std::transform as @AzP said:

std::transform(a, a + 5, b, [](double d) -> float {return float(d);});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文