Domanda

Aggiorna

OK, dopo alcune indagini, e grazie in gran parte alle risposte utili forniti da Jon e Hans, questo è quello che sono stato in grado di mettere insieme. Finora penso che sembra funzionare bene. Non ci scommetterei la mia vita sulla sua totale correttezza, naturalmente.

public static int GetSignificantDigitCount(this decimal value)
{
    /* So, the decimal type is basically represented as a fraction of two
     * integers: a numerator that can be anything, and a denominator that is 
     * some power of 10.
     * 
     * For example, the following numbers are represented by
     * the corresponding fractions:
     * 
     * VALUE    NUMERATOR   DENOMINATOR
     * 1        1           1
     * 1.0      10          10
     * 1.012    1012        1000
     * 0.04     4           100
     * 12.01    1201        100
     * 
     * So basically, if the magnitude is greater than or equal to one,
     * the number of digits is the number of digits in the numerator.
     * If it's less than one, the number of digits is the number of digits
     * in the denominator.
     */

    int[] bits = decimal.GetBits(value);

    if (value >= 1M || value <= -1M)
    {
        int highPart = bits[2];
        int middlePart = bits[1];
        int lowPart = bits[0];

        decimal num = new decimal(lowPart, middlePart, highPart, false, 0);

        int exponent = (int)Math.Ceiling(Math.Log10((double)num));

        return exponent;
    }
    else
    {
        int scalePart = bits[3];

        // Accoring to MSDN, the exponent is represented by
        // bits 16-23 (the 2nd word):
        // http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx
        int exponent = (scalePart & 0x00FF0000) >> 16;

        return exponent + 1;
    }
}

Non ho provato tutto ciò che bene. Ecco alcuni ingressi / uscite di esempio, se:

Value          Precision
0              1 digit(s).
0.000          4 digit(s).
1.23           3 digit(s).
12.324         5 digit(s).
1.2300         5 digit(s).
-5             1 digit(s).
-5.01          3 digit(s).
-0.012         4 digit(s).
-0.100         4 digit(s).
0.0            2 digit(s).
10443.31       7 digit(s).
-130.340       6 digit(s).
-80.8000       6 digit(s).

Con questo codice, immagino vorrei realizzare il mio obiettivo facendo qualcosa di simile a questo:

public static decimal DivideUsingLesserPrecision(decimal x, decimal y)
{
    int xDigitCount = x.GetSignificantDigitCount();
    int yDigitCount = y.GetSignificantDigitCount();

    int lesserPrecision = System.Math.Min(xDigitCount, yDigitCount);

    return System.Math.Round(x / y, lesserPrecision);
}

Non ho veramente finito di lavorare attraverso questo, però. Chiunque voglia pensieri di condivisione: che sarebbe molto apprezzato


Original domanda

Supponiamo che io ho scrivere questo codice:

decimal a = 1.23M;
decimal b = 1.23000M;

Console.WriteLine(a);
Console.WriteLine(b);

L'output volontà di cui sopra:

1.23
1.23000

Trovo che questo funziona anche se uso decimal.Parse("1.23") per a e decimal.Parse("1.23000") per b (il che significa che a questa domanda si applica ai casi in cui il programma riceve l'input dell'utente).

Quindi, chiaramente un valore decimal è in qualche modo "consapevole" di ciò che io chiamo il suo di precisione . Tuttavia, non vedo membri sul tipo decimal che forniscono alcun modo di accedere a questo, a parte ToString sé.

Supponiamo che io volevo per moltiplicare due valori decimal e tagliare il risultato alla precisione dell'argomento meno preciso. In altre parole:

decimal a = 123.4M;
decimal b = 5.6789M;

decimal x = a / b;

Console.WriteLine(x);

Le uscite precedenti:

21.729560302171195125816619416

Quello che mi chiedo è: come potrei scrivere un metodo che sarebbe tornato 21.73 invece (dal 123.4M ha quattro cifre significative)

Per essere chiari: realizzo ho potuto chiamare ToString su entrambi gli argomenti, contare le cifre significative in ogni stringa, e utilizzare questo numero per arrotondare il risultato del calcolo. Sto cercando un diverso modo, se possibile.

(I anche rendersi conto che nella maggior parte degli scenari in cui hai a che fare con le figure significative, probabilmente non è necessario essere utilizzando il tipo di decimal. Ma mi sto chiedendo perché, come ho già detto in principio, viene visualizzato il tipo decimal per includere informazioni sulla precisione, mentre double non lo fa, per quanto ne so.)

È stato utile?

Soluzione

È possibile utilizzare Decimal.GetBits per ottenere il dati grezzi, e il lavoro fuori da questo.

Purtroppo non ho il tempo di scrivere il codice di esempio in questo momento - e probabilmente desidera utilizzare BigInteger per alcuni di manipolazione, se si sta utilizzando .NET 4 - ma spero che questo ti porterà in corso. Basta lavorare fuori la precisione e quindi chiamando Math.Round sul risultato originale potrebbe essere un buon inizio.

Altri suggerimenti

Sì, a differenza di galleggiamento tipi di punti, System.Decimal tiene traccia del numero di cifre nel letterale. Questa è una caratteristica di decimal.Parse (), se eseguito dal codice voi stessi o dal compilatore quando si analizza un letterale nel vostro programma. È possibile recuperare queste informazioni, controllare il codice nella mia risposta in questa discussione .

mi Recuperare il numero di cifre significative dopo si fa la matematica sul valore colpisce come un colpo lungo. Non ho idea se gli operatori li conservano, per favore fateci sapere cosa si scopre.

La soluzione sopra cade dal letto rapidamente con valori come 1200 dove il numero di cifre significative è 2 ma la funzione restituisce 4. Forse c'è un modo coerente per affrontare una tale situazione IE controllare per non certo valore di ritorno non comprendono zeri nella porzione di numero intero senza una parte frazionaria.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top