2010-07-14 6 views
3

J'ai un problème avec la conversion de double en décimal:Conversion double pour décimal

public class CartesianCoordinates 
    { 
     public int LatitudeHours { get; set;} 
     public int LatitudeMinutes { get; set; } 
     public int LatitudeSeconds { get; set; } 
     public GeoDirectionLongtitude LongitudeDirection { get; set; } 

     public int LongitudeHours { get; set; } 
     public int LongitudeMinutes { get; set; } 
     public int LongitudeSeconds { get; set; } 
     public GeoDirectionLatitude LatitudeDirection { get; set; } 
    } 

public class DecimalCoordinates 
    { 
     public decimal Latitude { get; set; } 
     public decimal Longitude { get; set; } 
    } 

CartesianCoordinates CartesianCoordinates=new CartesianCoordinates(){LatitudeHours =12,LatitudeMinutes =34,LatitudeSeconds=56 } 

    converterDecimalCoordinates.Latitude = CartesianCoordinates.LatitudeHours + (CartesianCoordinates.LatitudeMinutes + (CartesianCoordinates.LatitudeSeconds/60))/60; 

Pourquoi je reçois 12? Je veux 12,55

Répondre

3

En tant que sous-produit de ma discussion avec David M et Daniel Brückner under this answer et la déclaration partiellement mal par moi-même sous this answer by Adam, il est devenu clair que, désolé de le dire, toutes les réponses sont seulement partiellement corrects. Ce qui se passe est la suivante:

// example (all x, y, z ar ints): 
Decimal d = x + y + z/60M; 

// is left to right evaluated as 
Decimal d = x + y + (((Decimal) z)/60M); 

// when doing addition, this is what happens when you add integers and something else: 
Decimal d = x + y + (int) (((Decimal) z)/60M); 

// which will yield a truncated result. 

Le résultat est le suivant: que le simple ajout d'un 60M ou 60.0 à l'ensemble de la déclaration, comme has been suggested, ne (ou non) donner le résultat souhaité, en fonction de l'ordre d'exécution du déclaration et/ou l'existence d'une addition/soustraction, comme c'est le cas dans la question du PO.

Pour résoudre ce problème, suivez les conseils d'Adam et convertir chaque addition/étape de soustraction à décimales, utiliser des décimales tout au long (pas très clair) ou placer le calcul dans une petite fonction qui prend décimaux en tant que paramètres, forçant la conversion implicite:

Decimal GetDecimalLatitude(Decimal latitudeHours, Decimal latitudeMinutes, Decimal latitudeSeconds) 
{ 
    return latitudeHours + (latitudeMinutes + (latitudeSeconds/60))/60; 
} 

qui, en prime, est plus courte et ajoute de la lisibilité. Appelez ceci avec la déclaration suivante:

converterDecimalCoordinates.Latitude = GetDecimalLatitude(
    CartesianCoordinates.LatitudeHours, 
    CartesianCoordinates.LatitudeMinutes, 
    CartesianCoordinates.LatitudeSeconds); 
+0

+1 pour la coulée implicite // claps de golf –

9

Tous vos calculs sont entiers et arrondis (plus exactement, tronqués). Essayez de remplacer vos valeurs littérales de 60 par 60m pour forcer un calcul décimal, ou 60.0 pour forcer un double calcul (auquel cas vous devrez convertir un nombre décimal à la fin).

+4

Juste une note, les valeurs ne sont pas arrondies dans le sens attendu - plus tronqué. 1.99 va lancer à 1 pour un int. –

3

Vous obtenez 12 parce que le calcul fonctionne sur int types pour certaines parties de celui-ci et n'est donc pas capable de contenir la précision - la valeur est tronquée à int. Je convertirais toutes vos valeurs en décimales avant de calculer - ou comme d'autres réponses l'ont suggéré, spécifiez vos littéraux en tant que nombres décimaux.

Mise à jour: comme l'a souligné dans d'autres postes, cela est en train d'effectuer une division entière - je ne connaissais pas le terme technique, donc comme vous, je l'ai appris quelque chose aujourd'hui lol

+1

Il suffit d'une décimale dans le calcul pour effectuer le calcul en décimal. Convertir chacun d'eux est un peu compliqué. – Abel

+0

Pour être honnête, je n'ai pas prêté trop d'attention aux détails dans le calcul lui-même - mais j'ai compris que la perte de précision était due à la division entière - d'autres réponses ont clarifié ce point. En outre, les calculs de ce type améliorent souvent la lisibilité au prix d'un peu de tracas, un bon compromis entre l'OMI. Je n'ai pas d'amour :-) –

+0

Je me suis trompé, en partie, et vous obtenez l'amour (et les crédits +1) que vous méritez, j'ai développé les commentaires dans une réponse ;-) – Abel

7
Int32 x = 10; 

Decimal y = x/4; // Performs an integer devision - result is 2.0 
Decimal z = x/4M; // Performs a decimal devision - result is 2.25 

Vous obtenez une déviation entière si les deux opérandes sont des entiers. En ajoutant le suffixe M à un nombre, vous pouvez explicitement indiquer que le nombre doit être interprété comme un nombre décimal et donc vous obtiendrez une déviation décimale.

+1

Je rencontre régulièrement 'Decimal x = 1M * [.. votre calcul ..] 'qui est un moyen rapide et facile d'améliorer la lisibilité et la robustesse contre l'édition par inadvertance en plaçant le littéral de conversion à l'avant. – Abel

+0

@Abel - n'aide pas, le calcul sera toujours effectué comme une division entière dans ce cas. La post-conversion en nombre décimal par multiplication n'affectera pas le résultat. –

+0

@David M: ça marche. Essayez cette instruction, elle donnera 2.5M dans 'x':' Decimal x = 1M * 5/2; '* (PS: Je vois maintenant ce que vous voulez dire: cela dépend du calcul et de l'ordre d'exécution, peut-être pas toujours une bonne idée alors) *. – Abel

1

Comme les autres déjà mentionnés, vous avez de chaque côté de votre division un entier. Donc le résultat est aussi un entier (qui sera ensuite implicite converti en un nombre décimal pour le côté gauche). Pour résoudre ce problème, un côté de votre division doit être une décimale, ce qui provoque la division décimale. Donc, essayez simplement cette ligne de code:

converterDecimalCoordinates.Latitude = CartesianCoordinates.LatitudeHours + (CartesianCoordinates.LatitudeMinutes + (CartesianCoordinates.LatitudeSeconds/60))/(decimal)60; 
Questions connexes