С++ разница между 0 и 0.0

Есть ли разница между 0 и 0.0 в С++? Что вы должны использовать для инициализации двойника?

Спасибо


person Community    schedule 05.09.2009    source источник


Ответы (4)


Литерал 0 считается литералом int; литерал 0.0 является литералом double. При назначении на double будет работать любой из них (поскольку int можно преобразовать в расширяющем преобразовании); однако приведение 0.0 к int является сужающим преобразованием и должно выполняться явно; то есть (int)0.0.

person Rob    schedule 05.09.2009
comment
0.0f — значение с плавающей запятой. :D - person Gordon Gustafson; 06.09.2009
comment
@Rob, ты хочешь сказать, что double нельзя неявно преобразовать в int? Рассмотрим int a = 0.0;. - person Johannes Schaub - litb; 06.09.2009
comment
Двойник наверняка может быть назначен int без явного приведения. Эту часть ответа необходимо пересмотреть. - person Brian Neal; 06.09.2009
comment
Может быть, Роб имеет в виду must в том смысле, чтобы избежать предупреждений о «вставьте сюда компилятор и флаги»? В случае константы, которая явно может быть представлена ​​в int, это кажется излишним. Но в целом преобразование из double в int опасно, потому что оно не определено для больших значений, поэтому я, безусловно, согласен с обобщением, что сужающие преобразования должны быть явными. - person Steve Jessop; 06.09.2009
comment
@onebyone Конечно, это может быть нежелательно, но это разрешено языком неявно без приведения. - person Brian Neal; 07.09.2009
comment
Я думаю, что приведение от 0 до 0.0 выполняется во время компиляции. Я прав? - person accfews; 17.06.2015

Я стараюсь, чтобы мои константы соответствовали типам. 0 для целых. 0.0f или 0.f для float и 0.0 для double.

На мой взгляд, наиболее важной причиной для этого является то, что компилятор и программист видят одно и то же.

Если я сделаю это...

float t=0.5f;
float r;

r= 1 * t;

...должен ли быть присвоен r 0 или .5? Без колебаний, если я сделаю это вместо этого...

float t=0.5f;
float r;

r= 1.0f * t;
person Nosredna    schedule 05.09.2009
comment
Да, у C проблемы, если он когда-нибудь захочет поддерживать шестнадцатеричные литералы с плавающей запятой, не так ли? :-) - person Nosredna; 06.09.2009
comment
Можете ли вы уточнить, пожалуйста? почему r когда-либо присваивался 0? - person pingu; 02.07.2012
comment
в первом случае значение 1 является целым числом и будет повышаться до того, как произойдет умножение. - person EvilTeach; 31.07.2018

Один из них представляет собой целочисленный литерал, а другой — литерал с плавающей запятой. Для компилятора действительно не имеет значения, инициализируете ли вы числа с плавающей запятой или удвоения целочисленными литералами. В любом случае литерал будет скомпилирован в некоторое внутреннее представление.

Я бы предложил 0.0, чтобы ваши намерения (для других программистов) были явно ясны.

person Jim Dennis    schedule 05.09.2009
comment
На самом деле это может иметь значение, потому что компилятор может вместо загрузки 0, которая является инструкцией за один цикл, компилятор может загрузить ноль из ПЗУ. С учетом сказанного, это было бы довольно глупо, но опять же, мы обезьяны. - person ; 31.07.2018

Вот разборка Visual-C++ для:

int main() {
  double x = 0;
  //
  double y = 0.0;
  //
  double z = x * y;
  return 0;
}

Разборка

int main() {
00007FF758A32230  push        rbp  
00007FF758A32232  push        rdi  
00007FF758A32233  sub         rsp,128h  
00007FF758A3223A  mov         rbp,rsp  
00007FF758A3223D  mov         rdi,rsp  
00007FF758A32240  mov         ecx,4Ah  
00007FF758A32245  mov         eax,0CCCCCCCCh  
00007FF758A3224A  rep stos    dword ptr [rdi]  
  double x = 0;
00007FF758A3224C  xorps       xmm0,xmm0  
00007FF758A3224F  movsd       mmword ptr [x],xmm0  
  //
  double y = 0.0;
00007FF758A32254  xorps       xmm0,xmm0  
00007FF758A32257  movsd       mmword ptr [y],xmm0  
  //
  double z = x * y;
00007FF758A3225C  movsd       xmm0,mmword ptr [x]  
00007FF758A32261  mulsd       xmm0,mmword ptr [y]  
00007FF758A32266  movsd       mmword ptr [z],xmm0  
  return 0;
00007FF758A3226B  xor         eax,eax  
}
00007FF758A3226D  lea         rsp,[rbp+128h]  
00007FF758A32274  pop         rdi  
00007FF758A32275  pop         rbp  
00007FF758A32276  ret

Выпустили такую ​​же сборку. Visual-C++ использует метод XOR-соединения регистра XMM с самим собой. Если бы вы сначала загрузили целое число 0, а затем переместили его в регистр XMM, потребовалась бы дополнительная инструкция. Учитывая нашу гипотезу о том, как 0.0 может быть загружен как литерал, а также дополнительную бесполезную загрузку инструкций, загружающую целое число 0, а затем перемещая его в регистр с плавающей запятой, ни один из них не является оптимальным, поэтому кажется, что это действительно не имеет значения. потому что автор компилятора, мы должны предположить, что эта оптимизация была известна в течение длительного времени, потому что она очевидна. Если требуется 100% переносимость, то более переносимым будет написать встроенную функцию, которая вручную использует метод XOR.

person Community    schedule 31.07.2018