2012-08-30 16 views
17

Attualmente sto lavorando a un progetto C++ che esegue calcoli numerici. La vasta, vasta maggioranza del codice utilizza valori di virgola mobile a precisione singola e funziona perfettamente bene con quello. Per questo motivo utilizzo i flag del compilatore per rendere i valori letterali in virgola mobile di base a precisione singola invece della doppia precisione, che è l'impostazione predefinita. Trovo che ciò renda le espressioni più facili da leggere e non devo preoccuparmi di dimenticare una "f" da qualche parte. Tuttavia, ogni tanto ho bisogno della precisione extra offerta da calcoli a doppia precisione e la mia domanda è come riesca a ottenere una doppia precisione letterale in tale espressione. Ogni modo che ho provato finora memorizza il valore in una singola variabile di precisione e converte il valore troncato in un doppio valore di precisione. Non quello che voglio.Esiste un suffisso letterale in virgola mobile in C++ per fare una precisione doppia al numero?

Alcuni metodi che ho provato fino ad ora sono riportati di seguito.

#include <iostream> 

int main() 
{ 
    std::cout << sizeof(1.0E200) << std::endl; 
    std::cout << 1.0E200 << std::endl; 

    std::cout << sizeof(1.0E200L) << std::endl; 
    std::cout << 1.0E200L << std::endl; 

    std::cout << sizeof(double(1.0E200)) << std::endl; 
    std::cout << double(1.0E200) << std::endl; 

    std::cout << sizeof(static_cast<double>(1.0E200)) << std::endl; 
    std::cout << static_cast<double>(1.0E200) << std::endl; 

    return 0; 
} 

Una corsa con costanti di precisione singola fornisce i seguenti risultati.

~/path$ g++ test.cpp -fsingle-precision-constant && ./a.out 
test.cpp:6:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:7:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:12:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:13:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:15:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
test.cpp:16:3: warning: floating constant exceeds range of ‘float’ [-Woverflow] 
4 
inf 
16 
1e+200 
8 
inf 
8 
inf 

rimane inteso che gli 8 byte forniti dai due ultimi casi dovrebbe essere sufficiente a contenere 1.0E200, una teoria sostenuta dalla seguente output, dove lo stesso programma viene compilato senza -fsingle precisione costante .

~/path$ g++ test.cpp && ./a.out 
8 
1e+200 
16 
1e+200 
8 
1e+200 
8 
1e+200 

Una possibile soluzione suggerita dai suddetti esempi è di usare precisione quadrupla letterali punto ovunque originariamente destinato ad utilizzare doppia precisione, e cast a doppia precisione se richiesto da biblioteche e tale galleggiante. Tuttavia, questo sembra un po 'dispendioso.

Cos'altro posso fare?

+0

Soluzioni collaudate, ma 'strtod ("1e + 200") 'potrebbe essere ottimizzato per la costante a virgola mobile a doppia precesione desiderata. –

+4

Non so, sembra un po 'come se stessi creando un problema. Perché non lasciarlo così com'è e aggiungere 'f' a tutto ciò che non ha bisogno della doppia precisione? – Mysticial

+1

Puoi mettere le tue doppie costanti in un file separato e compilarlo senza il flag '-fsingle-precision-constant'. –

risposta

19

Come ha detto Mark, lo standard dice che è un doppio se non è seguito da un f.

Ci sono buone ragioni dietro lo standard e l'utilizzo dei flag del compilatore per aggirare il problema per praticità è una cattiva pratica.

Quindi, l'approccio corretto sarebbe:

  1. Rimuovere il flag di compilazione
  2. risolvere tutti gli avvertimenti sulla perdita di precisione quando si ripone valori doppi in floating variabili virgola (aggiungere in tutti i suffissi f)
  3. Quando è necessario il doppio, omettere il suffisso f.

sua probabilmente non è la risposta che stavate cercando, ma è l'approccio che si dovrebbe usare se vi preoccupate per la longevità del vostro codice di base.

+0

Quali sono esattamente queste "buone ragioni"? Sembra più una limitazione che rende difficile quella bandiera particolare. Inoltre, cosa c'è di sbagliato nell'usare 'double (1.0E200L)'? Come influisce la longevità? –

+0

Una base di codice non dovrebbe essere limitata a un compilatore specifico. Un compilatore dovrebbe essere conforme a uno standard. Uno standard dovrebbe essere l'unica fonte di verità. Implica la longevità perché non conforme allo standard introduce nel tempo incongruenze come i vari programmatori lavorano sulla base del codice e ognuno fa le cose nel modo che preferiscono. Questa è la ragione per cui esistono gli standard. – Carl

11

Se andate a leggere 2.13.3/1 si vedrà:

Il tipo di un letterale galleggiante è doppio se non esplicitamente specificato da un suffisso. I suffissi f e F specificano float, i suffissi l e L specificano il doppio lungo.

In altre parole non v'è alcun suffisso per specificare double per una virgola mobile letterale costante se si modifica l'impostazione predefinita per float. Sfortunatamente non puoi avere il meglio di entrambi i mondi in questo caso.

+1

-1, 'double (1.0E200L)' funziona correttamente. – orlp

+0

Non importa, il richiedente l'ha proposto nella domanda e l'ha trovato "dispendioso". – orlp

5

Non è possibile definire il proprio suffisso, ma forse una macro come

#define D(x) (double(x##L)) 

avrebbe funzionato per voi. Il compilatore dovrebbe emettere solo una doppia costante e appare con -O2 sul mio sistema.

+0

+1 solo per verificare che il compilatore emetta una doppia costante, che ero troppo pigro per fare quando ho commentato la domanda per dire che sarebbe :-) –

8

Se lo può permettere GCC 4.7 o Clang 3.1, utilizzare un definito dall'utente letterale:

double operator "" _d(long double v) { return v; } 

Usage:

std::cout << sizeof(1.0E200_d) << std::endl; 
std::cout << 1.0E200_d << std::endl; 

Risultato:

8 
1e+200 
Problemi correlati