С++ memcpy из двойного массива в плавающий массив

Можно ли безопасно memcpy из двойного массива в массив float?

Ответ 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);});