O que é a carcaça da ordem de operações na aritmética em c++?

0

Pergunta

Por que

  1. result = static_cast<double>(1 / (i+1))

retorno int em C++, e por que

  1. result = 1 / (i+static_cast<double>(1))

retorno double? Especificamente, qual é a carcaça após a +-operação suficiente para produzir um double. Por que não é necessário, antes de o + ou no numerador como assim? É static_cast a melhor maneira de fundição?

Código:

double harmonic(int n) {
  double result = 0;
  for (int i = 0; i < n; i++) {
    result += 1 / static_cast<double>(i+1);
  }
  return result;
}
arithmetic-expressions c++ casting types
2021-11-21 13:17:43
3

Melhor resposta

2

Não há nenhuma tal coisa como a "carcaça de ordem", porque o tipo de uma expressão depende de seus operandos. Colocá-lo simplesmente, se um operador aritmético binário aceita dois operandos de diferentes tipos, em seguida, do tipo menor vai ser implicitamente convertido para o tipo maior

No result = static_cast<double>(1 / (i+1)) é analisado como este

  • i + 1 é um int expressão uma vez que ambos i e 1 são do tipo int
  • 1 / (i + 1) retorna int, pela mesma razão
  • Em seguida, o resultado da 1 / (i + 1) é estaticamente o elenco double

OTOH em result = 1 / (i+static_cast<double>(1)) é como se essa

  • 1 é o elenco double
  • i + static_cast<double>(1) retorna double porque i é o elenco double devido para o outro operando
  • 1 / (i+static_cast<double>(1)) é um double expressão para a mesma razão

Mas não um elenco como esse. É melhor fazer 1 / (i + 1.0) em vez disso

O completo regra é assim

  • Se um dos operandos tem como escopo tipo de enumeração, nenhuma conversão é realizada: o outro operando e o tipo de retorno deve ter o mesmo tipo de
  • Caso contrário, se um dos operandos for long double, o outro operando é convertido para long double
  • Caso contrário, se um dos operandos for double, o outro operando é convertido para double
  • Caso contrário, se um dos operandos for float, o outro operando é convertido para float
  • Caso contrário, o operando tem tipo inteiro (porque bool, char, char8_t, char16_t, char32_t, wchar_te sem escopo de enumeração foram promovidos neste ponto) e integrante conversões são aplicadas para produzir o tipo comum, como segue:
    • Se ambos os operandos forem assinados ou ambos não são assinados, operando com menor conversão rank é convertido para a operando com o maior número inteiro de conversão classificação
    • Caso contrário, se não assinados operando a conversão rank é maior ou igual a conversão da classificação dos assinado operando, assinado operando é convertido para unsigned operando do tipo.
    • Caso contrário, se o assinaram operando de tipo pode representar todos os valores da unsigned operando, a não assinados operando é convertido para a assinatura do operando do tipo
    • Caso contrário, ambos os operandos são convertidos para não assinados contrapartida das assinado operando do tipo.

A conversão da classificação acima aumenta na ordem de bool, signed char, short, int, long, long long. A classificação de qualquer tipo não assinado é igual ao posto de correspondente, assinado tipo. O rank de char é igual ao posto de signed char e unsigned char. As fileiras de char8_t, char16_t, char32_te wchar_t são iguais para as fileiras de seus subjacente tipos.

Operadores aritméticos

2021-11-21 13:34:10

Ótimo, obrigado! Esta é exatamente a resposta que eu estava procurando. Eu encontrei o truque com o 1.0 especialmente útil!
DataFace
1
static_cast<double>(1 / (i+1));

Primeiro, 1 / (i+1) obter avaliar. Porque 1 é um int e i+1 é um int, então esta é a divisão de número inteiro, de modo 1/(i+1) é um int. O resultado é, então, estigmatizado em um double. Então, tecnicamente, static_cast<double>(1 / (i+1)); retorna um double, mas o resultado é perdida devido a 1/(i+1) é a divisão de número inteiro

result += 1 / static_cast<double>(i+1);

Agora porque static_cast<double>(i+1) é uma dupla, 1 / static_cast<double>(i+1); agora é ponto flutuante divisão, assim 1 / static_cast<double>(i+1); é um double

2021-11-21 13:26:20

E, é claro, 1.0 /(i + 1) é ainda melhor.
Pete Becker
1

Você deve estar ciente do Inteiro Divisão

Você pode usar esse código para ver, que, na verdade, retorna um double. No entanto, devido à divisão de número inteiro, ele será sempre zero (ou nan).

#include <iostream>

using std::cout;

int main()
{
    int i = 5;
    cout << typeid(static_cast<double>(1 / (i+1))).name() << "\n"; // d for double
    return 0;
}

Você pode contornar a divisão de número inteiro, por que não dividir dois números inteiros. Para os mesmos é o suficiente, se um deles é double.

int + double == double
double + int == double
int / double == double
double / int == double

Assim você pode ver, basta apenas lançar um summand para o casal, a fim de transformar toda a expressão em uma de casal, o que não é sempre zero.

2021-11-21 13:30:50

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................