Is is possible to memcpy from a double array to a float array safely?
5 Answers
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);
}

- 256,549
- 94
- 388
- 662
-
This does not work (for me on VS2017) since the compiler does not allow the implicit loss of precision from double to float via `std::copy`. I had to use the `std::transform` function instead, using a lamda. This also clearer shows that an explicit loss-of-precision is actually taking place. – AzP May 31 '18 at 08:13
-
@AzP it sounds like you've chosen compiler options to make it reject valid code then. (Or there's a compiler bug) – M.M Dec 18 '18 at 22:13
-
1@M.M well, implicit loss of precision is a bit dangerous - depending on what you are working with - and using a warning level of 4 will result in a compiler warning. Since I'm using 'treat warnings as errors' it won't compile. "Valid code" in this sense doesn't mean 'good code'. – AzP Dec 19 '18 at 10:40
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.

- 56,849
- 17
- 98
- 154
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); });

- 1,081
- 1
- 16
- 27
-
1Your problem is this "treat warnings as errors" nonsensical option. Sure, `transform` works, is more explicit, and thus might be preferred in some code bases, but "does not work" for `copy` is clearly wrong. – Marc Glisse May 31 '18 at 08:42
-
1@MarcGlisse, true, I'll change that wording. I disagree with the option being "nonsensical" though. – AzP May 31 '18 at 09:04
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.

- 312,472
- 42
- 525
- 765
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);});

- 10,089
- 6
- 61
- 69