2008-11-03 8 views
1

Check it out: ce petit programme de console .NET donne des résultats intéressants ... Remarquez comment je convertir un flotteur en entier de deux façons différentes:. Bogue .NET lors de la conversion de float en entier?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace CastVsConvert 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int newWidth = 0; 
      CalculateResizeSizes(600, 500, out newWidth); 
     } 

     static void CalculateResizeSizes(int originalWidth, int maxWidth, out int newWidth) 
     { 
      float percentage = 1.0F; 
      percentage = maxWidth/(float)originalWidth; 

      newWidth = (int)((float)originalWidth * percentage); 
      int newWidthConvert = Convert.ToInt32((float)originalWidth * percentage); 

      Console.Write("Percentage: {0}\n", percentage.ToString()); 
      Console.Write("Cast: {0}\n", newWidth.ToString()); 
      Console.Write("Convert: {0}\n", newWidthConvert.ToString()); 
     } 
    } 
} 

je me attends à la sortie de « Cast » et « Convert » pour être le même, mais ils ne sont pas ... voici la sortie:

C:\Documents and Settings\Scott\My Documents\Visual Studio 2008\Projects\CastVsC 
onvert\CastVsConvert\bin\Debug>CastVsConvert.exe 
Percentage: 0.8333333 
Cast: 499 
Convert: 500 

Quelqu'un sait-il pourquoi .NET est de retour des valeurs différentes ici?

Répondre

5

La distribution supprime la partie du nombre après la virgule décimale pendant l'arrondi.

14

Ce n'est pas un bug, cast tronque, convert tours.

Voir this

5

De la documentation pour la valeur de retour de Convert.ToInt32:

valeur arrondi au 32 bits le plus proche entier signé. Si la valeur est à mi-chemin entre deux nombres entiers, le nombre pair est renvoyé; à savoir, 4.5 est converti en 4 et 5.5 est converti à 6.

Coulée n'arrondit pas - juste tronque. Le résultat de la multiplication est très légèrement inférieur à 500, donc le moulage tronquera à 499 alors que Convert.ToInt32 l'arrondira à 500.

1

Il y a une distribution cachée supplémentaire qui est probablement à l'origine de cela. Par exemple, si vous l'utilisez à la place d'un recalcul:

int newWidthConvert = Convert.ToInt32(newWidth); 

Vous obtiendrez le même résultat. Ce qui se passe devient plus clair lorsque vous utilisez réflecteur pour avoir un aperçu Convert.ToInt32(float):

public static int ToInt32(float value) 
{ 
    return ToInt32((double) value); 
} 

Il y a un casting caché à Double.

Si vous ajoutez quelques lignes à étudier, puis utiliser le débogueur pour jeter un oeil, vous verrez ce qui se passe:

float newWidth1 = ((float)originalWidth * percentage); 
double newWidth2 = ((float)originalWidth * percentage); 

double est plus précise et enregistre la valeur 499,999999 et quelques plus de chiffres décimaux. float est moins précis et stocke 500.0. La conversion d'entier tronque la partie décimale, de sorte que vous finissez avec 500 ou 499 basé sur la distribution intermédiaire. Lorsque vous appelez Convert.ToInt32(), le résultat est déjà converti en float, ce qui vous donne la représentation Double de 500,0. Personnellement, je préfère toujours utiliser double quand je peux.

Questions connexes