Vraag C ++ memcpy van dubbele array naar float-array


Is het mogelijk om veilig van een dubbele array naar een float-array te memcpy?


10
2018-06-02 15:18


oorsprong


antwoorden:


Afhankelijk van wat je wilt. De waarden zullen zeker niet worden bewaard. Als je dat nodig hebt, gebruik dan 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);
}

31
2018-06-02 15:19



Nee.


26
2018-06-02 15:20



Het probleem is dat er geen garantie is dat de binaire weergave van een double is de equivalente weergave van een float. Om te kunnen gebruiken memcpy voor multi-byte typen is dat de onderliggende representatie hetzelfde moet zijn (dezelfde lay-out). Je kunt veilig kopiëren float naar float, int naar int en double naar double.

Je bent voorbestemd ongedefinieerd gedrag wanneer het brontype niet overeenkomt met het bestemmingstype, zoals kopiëren van long naar char of float naar double. De memcpy functie maakt geen enkele conversie of voert geen promoties uit. Het kopieert gewoon.


3
2018-06-02 16:41



In het algemeen geval - nr.

In specifieke gevallen is op een bepaald platform de weergave van float en double kan hetzelfde zijn, en de kopie zal slagen. Maar het is hoe dan ook geen praktische zin.


1
2018-06-02 16:52



Zoals vele anderen hebben beantwoord, gebruiken memcpy werkt niet omdat de twee typen (in het algemeen) van verschillende grootte zijn. Zie meer op http://en.cppreference.com/w/cpp/language/types, of meer specifiek:

Drijvende-komma-typen

vlotter - type drijvende komma met enkele precisie.   Meestal IEEE-754 32-bits drijvende-kommatype

dubbele - type drijvende-komma met dubbele precisie. Meestal IEEE-754 64-bits drijvende-kommatype

lang dubbel - type met drijvende komma met verlengde precisie. Komt niet noodzakelijk overeen met typen die zijn verplicht gesteld door IEEE-754. Gewoonlijk 80-bits x87 drijvende-kommatype op x86- en x86-64-architecturen.

Gebruik makend van std::copy geeft je een compileerwaarschuwing (tenminste voor mij op de VS2015 / VS2017-compiler) omdat de compiler het impliciete verlies van precisie niet toelaat van double to float via std :: copy, zonder de ontwikkelaar erover te waarschuwen. En als u de treat warnings as errors flag set, krijg je een compileerfout.

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

In plaats daarvan raad ik aan het gebruik van de std::transform functie, gecombineerd met een lamda die de specifieke cast uitvoert. Dit geeft ook duidelijk aan dat er expliciet verlies van precisie plaatsvindt.

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
2018-05-31 08:30