A way of writing large numeral literals in C#

2019-06-22 13:51发布

问题:

I have a method like this:

Prefix GetPrefix(decimal value)
{
    if(value > 11000000000000000000)
        return Prefix.CosmicBig;
    if(value > 1000000000000000)
        return Prefix.ReallyBig;
    if(value > 3000000000000)
        return Prefix.Big;
    if(value > 50000000)
        return Prefix.Okay;
    if(value > 750000)
        return Prefix.MostlyNormal;
    if(value > 750000)
        return Prefix.SoSo;
    if(value > 750)
        return Prefix.Small;
    return Prefix.MiserablySmall;
}

The exact values are not important. What matters is that they are sometimes changed (the prefixes are used for drawing and some text areas change sizes in development). I'm looking for a way of writing these literals in a way that's easily readably by a human changing it, without having to count all the zeroes. A separator would be nice. I thought about writing 11 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, but that's only barely more manageable. Using Math.Pow() does it a little better, but I'm not comfortable with using such calculations to define constants.

回答1:

You can introduce extension methods for int:

750.Thousand();
5.Million();
100.Billion();

The implementation of these methods is simple:

public static int Thousand(this int value)
{
    return value * 1000;
}

public static int Million(this int value)
{
    return value.Thousand() * 1000;
}

// etc.

Make sure to return the appropriate data type for methods for bigger numbers:

public static long Billion(this int value)
{
    return value.Million() * 1000;
}

Unfortunatelly, you will have to write those methods for every integral or floating point type you want to support.

Having a full set of such extension methods would allow you to express your large numbers in relativly natural ways, even when it's not just all zeros at the end:

100.Billion() + 30.Thousand() + 300 // == 100,000,030,300

If you want to get fancy, you could even think about nesting them:

100.Billion(30.Thousand(300))

But I think that would lose some expressiveness, because people would wonder what the parameter means.

Still, implementation would look like this:

public static long Billion(this int value, long add)
{
    return value.Million() * 1000 + add;
}

Using these extension methods has one little downside: Your numbers are no longer compile-time constants. They are calculated at runtime. In the vast majority of cases, this shouldn't be a problem.



回答2:

Instead of 11000000000000000000 you can use 11e18. Use m to indicate that it is a decimal, so 11e18m.