Можно ли безопасно memcpy из двойного массива в массив float?
С++ memcpy из двойного массива в плавающий массив
Ответ 1
Зависит от того, что вы хотите. Значения, безусловно, не будут сохранены. Если вам это нужно, используйте 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);
}
Ответ 2
Нет.
Ответ 3
Проблема заключается в том, что нет гарантии, что двоичное представление компилятора a double
является эквивалентным представлением float
. Для использования memcpy
для многобайтовых типов следует, что базовое представление должно быть одинаковым (тот же макет). Вы можете безопасно скопировать float
в float
, int
в int
и double
в double
.
Вы предназначены для поведения undefined, когда тип источника не соответствует типу назначения, например, копирование от long
до char
или float
до double
. Функция memcpy
не выполняет никаких преобразований и не выполняет никаких рекламных акций. Он просто копирует.
Ответ 4
Как и многие другие ответили, использование memcpy
не работает, так как два типа (как правило) различаются по размеру. Пожалуйста, смотрите больше на http://en.cppreference.com/w/cpp/language/types, или более конкретно:
Типы с плавающей точкой
float - тип с плавающей точкой одинарной точности. Обычно IEEE-754 32-битный тип с плавающей точкой
двойной - тип двойной точности с плавающей точкой. Обычно IEEE-754 64-битный тип с плавающей точкой
long double - расширенная точность типа с плавающей точкой. Не обязательно соответствует типам, предписанным IEEE-754. Обычно 80-битный тип x87 с плавающей точкой на архитектурах x86 и x86-64.
Использование std::copy
выдаст вам предупреждение компилятора (по крайней мере, для меня на компиляторе VS2015/VS2017), так как компилятор не допускает неявную потерю точности от double до float через std :: copy, не предупреждая об этом разработчика, И если у вас установлен флаг 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
сочетании с лямдой, выполняющей конкретное приведение. Это также более ясно показывает, что в действительности имеет место явная потеря точности.
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); });
Ответ 5
В общем случае - нет.
В конкретных случаях на данной платформе представление float
и double
может быть одинаковым, и копия будет успешной. Но в любом случае это не имеет никакого практического смысла.
Ответ 6
memcpy
зависит от типа (просто видит байты) и не может выполнять преобразование типов. Просто используйте std::transform
как @AzP сказал:
std::transform(a, a + 5, b, [](double d) -> float {return float(d);});