Je veux augmenter la plus petite partie fractionnaire d'un décimal de un de sorte que par exemple
decimal d = 0.01
d++
d == 0.02
ou
decimal d = 0.000012349
d++
d == 0.000012350
Comment puis-je faire cela?
Je veux augmenter la plus petite partie fractionnaire d'un décimal de un de sorte que par exemple
decimal d = 0.01
d++
d == 0.02
ou
decimal d = 0.000012349
d++
d == 0.000012350
Comment puis-je faire cela?
Le type décimal (.NET 2.0 et ultérieur) conserve des zéros significatifs en fin de nombre qui sont le résultat d'un calcul ou du parsing d'une chaîne. Par exemple, 1,2 * 0,5 = 0,60 (la multiplication de deux nombres précis à une décimale donne un résultat précis à 2 décimales, même lorsque la deuxième décimale est zéro) :
decimal result = 1.2M * 0.5M;
Console.WriteLine(result.ToString()); // affiche 0.60
Le code suivant suppose que vous souhaitez prendre en compte tous les chiffres significatifs de votre valeur décimale, c'est-à-dire :
decimal d = 1.2349M; // original 1.2349;
d = IncrementLastDigit(d); // le résultat est 1.2350;
d = IncrementLastDigit(d); // le résultat est 1.2351; (pas 1.2360).
Cependant, si vous souhaitez d'abord supprimer les zéros en fin de nombre, vous pouvez le faire, par exemple en utilisant la technique dans cette réponse.
Il n'y a rien de prévu pour le faire automatiquement. Vous devrez le faire vous-même en (a) déterminant combien de chiffres se trouvent après la virgule, puis (b) ajoutant la quantité appropriée.
Pour déterminer combien de chiffres se trouvent après la virgule, vous pouvez soit formater en tant que chaîne, puis les compter, soit plus efficacement, appeler decimal.GetBits(), dont le résultat est un tableau de quatre entiers qui contient le facteur d'échelle dans les bits 16-23 du quatrième entier.
Une fois que vous avez cela, vous pouvez facilement calculer la valeur requise à ajouter à votre valeur décimale.
Voici une implémentation qui utilise GetBits, qui "incrémente" en s'éloignant de zéro pour les nombres négatifs IncrementLastDigit(-1.234M) => -1.235M.
static decimal IncrementLastDigit(decimal value)
{
int[] bits1 = decimal.GetBits(value);
int saved = bits1[3];
bits1[3] = 0; // Définir l'échelle à 0, supprimer le signe
int[] bits2 = decimal.GetBits(new decimal(bits1) + 1);
bits2[3] = saved; // Restaurer l'échelle et le signe d'origine
return new decimal(bits2);
}
Ou voici une alternative (peut-être légèrement plus élégante) :
static decimal GetScaledOne(decimal value)
{
int[] bits = decimal.GetBits(value);
// Générer une valeur +1, mise à l'échelle en utilisant le même facteur d'échelle que la valeur d'entrée
bits[0] = 1;
bits[1] = 0;
bits[2] = 0;
bits[3] = bits[3] & 0x00FF0000;
return new decimal(bits);
}
static decimal IncrementLastDigit(decimal value)
{
return value < 0 ? value - GetScaledOne(value) : value + GetScaledOne(value);
}
J'ai trouvé une nouvelle solution qui est différente de celle de Joe, cela devrait entraîner une légère augmentation des performances.
public static decimal IncrementLowestDigit(this decimal value, int amount)
{
int[] bits = decimal.GetBits(value);
if (bits[0] < 0 && amount + bits[0] >= 0)
{
bits[1]++;
if (bits[1] == 0)
{
bits[2]++;
}
}
bits[0] += amount;
return new decimal(bits);
}
Test
J'ai testé mes résultats avec les méthodes de Joe.
private static void Test(int l, int m, int h, int e, int times)
{
decimal a = new decimal(new[] { l, m, h, e });
decimal b = a.IncrementLowestDigit(times);
decimal c = IncrementLastDigit(a, times);
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine();
}
Test(0, 0, 0, 0x00000000, 1);
Test(0, 0, 0, 0x00000000, 2);
Test(0, 0, 0, 0x00010000, 1);
Test(0, 0, 0, 0x00010000, 2);
Test(0, 0, 0, 0x00020000, 1);
Test(0, 0, 0, 0x00020000, 2);
Test(-1, 0, 0, 0x00000000, 1);
Test(-1, 0, 0, 0x00000000, 2);
Test(-1, 0, 0, 0x00010000, 1);
Test(-1, 0, 0, 0x00010000, 2);
Test(-1, 0, 0, 0x00020000, 1);
Test(-1, 0, 0, 0x00020000, 2);
Test(-2, 0, 0, 0x00000000, 1);
Test(-2, 0, 0, 0x00000000, 2);
Test(-2, 0, 0, 0x00010000, 1);
Test(-2, 0, 0, 0x00010000, 2);
Test(-2, 0, 0, 0x00020000, 1);
Test(-2, 0, 0, 0x00020000, 2);
Test(-2, 0, 0, 0x00000000, 3);
Test(0, 1, 0, 0x00000000, 1);
Test(0, 1, 0, 0x00000000, 2);
Test(0, 1, 0, 0x00010000, 1);
Test(0, 1, 0, 0x00010000, 2);
Test(0, 1, 0, 0x00020000, 1);
Test(0, 1, 0, 0x00020000, 2);
Test(-1, 2, 0, 0x00000000, 1);
Test(-1, 2, 0, 0x00000000, 2);
Test(-1, 2, 0, 0x00010000, 1);
Test(-1, 2, 0, 0x00010000, 2);
Test(-1, 2, 0, 0x00020000, 1);
Test(-1, 2, 0, 0x00020000, 2);
Test(-2, 3, 0, 0x00000000, 1);
Test(-2, 3, 0, 0x00000000, 2);
Test(-2, 3, 0, 0x00010000, 1);
Test(-2, 3, 0, 0x00010000, 2);
Test(-2, 3, 0, 0x00020000, 1);
Test(-2, 3, 0, 0x00020000, 2);
Juste pour rire
J'ai effectué un test de performance avec 10 millions d'itérations sur une puce Intel de 3 Ghz :
Le mien : 11.6 ns
Celui de Joe : 32.1 ns
Que diriez-vous de ceci :
static class DecimalExt {
public static decimal PlusPlus(this decimal value) {
decimal test = 1M;
while (0 != value % test){
test /= 10;
}
return value + test;
}
}
class Program {
public static void Main(params string[] args) {
decimal x = 3.14M;
x = x.PlusPlus(); // maintenant c'est 3.15
}
}
J'ai utilisé une méthode d'extension ici; vous ne pouvez pas redéfinir l'opérateur ++ pour le type decimal.
Cela ferait l'affaire :
decimal d = 0.01M;
int incr = 1;
int pos = d.ToString().IndexOf('.');
int len = d.ToString().Length - pos - 1;
if (pos > 0)
{
double val = Convert.ToDouble(d);
val = Math.Round(val * Math.Pow(10, len) + incr) / Math.Pow(10, len);
d = Convert.ToDecimal(val);
}
else
d += incr;
return d;
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.