none
How to test last two digits in decimal variables with different precisions

    Question

  • I've got a decimal variable with a currency rate that can come in one of two ways; if it's about Yen then the value will be something like 110.50 or 110.00, but if it's about most any other currency rate it will be something like 0.7100 or 0.7050.

    I need to figure out in code whether the order is a "50 or a 100" referring to the two last digits. What's the smart way of doing this?

    TIA

    Dennis

    Thursday, March 30, 2017 8:39 PM

Answers

  • int _0th=decimal.GetBits(yourDecimalNumber)[0]; 
    bool b100=_0th%100==0,b50=_0th%50==0; 
    Console.WriteLine("ENDS WITH {0}",b100?"00":b50?"50":"none");
    

    ISN'T THE SMART CODE RIDICULOUSLY SIMPLE?

    It is just a matter of implementing it using C# and not rubbish#...

    • Marked as answer by sgude1 Friday, March 31, 2017 7:35 PM
    Friday, March 31, 2017 7:29 PM

All replies

  • What you're referring to as the precision is only the string-based representation you may be seeing. Under the hood that value could potentially be different. Also note that you said the last 2 digits but 100 is 3 digits. So my first question would be what format are you getting the original value in - string, decimal, etc? If it is a string then you should probably do your processing before converting to a decimal.

    However if it is a decimal then you'll likely want to round the value to the precision you want first. For example if you want to ensure that you're only dealing with 3 digits of precision to the right of the decimal then use Math.Round. That would normalize your value so you could now look at the values consistently (.500 or .000 or .710 or .705).

    Ideally if you can solve this problem by simply using ranges of values then it would probably be better. For example if you want to know whether a value is 0.7100 vs 0.7050 then it would be easier to use range checking like (x >= 0.700 && x < 0.7100). Ignoring rounding concerns this would give you what you want.

    If you really need the fractional parts as is then you're best bet is to probably simply convert it to a string with the specifier to force a certain precision range. Then you can grab everything to the right of the decimal. But given rounding issues and whatnot I'm not sure the results will be what you want unless you can be sure of the format(s) you're going to be getting.

    Perhaps if you could clarify why you need to do this we can provide better suggestions.

    Michael Taylor
    http://www.michaeltaylorp3.net

    Thursday, March 30, 2017 9:17 PM
    Moderator
  • These are currency rates, and they come in two versions, four decimals for non-yen pairs, and two decimal for all others (almost). The decimals are called "pips", but whether they use two or four decimals vary with the currency pair involved, hence I need to somehow be open to both versions.

    In a yen pair 110.00 would be a "hundred" and 110.50 would be a "fifty" (110.50 to 111.00 is 50 pips), while for say GBP 1.2500 would also be a "hundred" and 1.2550 would be a "fifty" (1.2500 to 1.2550 is also 50 pips).

    The incoming variable is of type decimal. I do have access to a second decimal variable called UsePoint which would be 0.01 if the pair only has two decimals, but 0.0001 if it has four.

    Does that clear up the issue?

    Re

    Dennis


    • Edited by sgude1 Thursday, March 30, 2017 9:37 PM
    Thursday, March 30, 2017 9:32 PM
  • Yes it does but I don't promise my math is going to be quite correct. Given the UsePoint variable you know whether you're dealing with 2 or 4 digits of precision. Use that to convert the value to "pips", then use normal math.

    decimal ToPips ( decimal value, int precision )
    {
       return value * (Math.Power(10, precision));
    }
    
    var yen1 = ToPips(110.00, 2) => 110 * (10^2) = 11000;
    var yen2 = ToPips(110.50, 2) => 110.50 * (10^2) = 11050;
    
    var yenDifferenceInPips = yen1 - yen2;
    
    var pound1 = ToPips(1.2500, 4) => 1.25 * (10^4) = 12500;
    var pound2 = ToPips(1.2550, 4) => 1.255 * (10^4) = 12550;
    
    var poundDifferenceInPips = pound1 - pound2;

    So basically this normalizes things. The more challenging aspect will be if you want to compare different "units". In this case you'll probably want to wrap this in an actual type that also tracks the "precision". Something to get you started (won't compile as is but should get you started).

    public struct Pip
    {
       public Pip ( decimal value, int precision )
       {
          Value = value;
          Precision = precision;
       }
    
       //Can create overloaded operators as needed
       public Pip Add ( Pip value2 )
       {
          //If the precision matches then just add them
          if (Precision == value2.Precision)
             return new Pip(Value + value2.Value, Precision);
    
          //Pick the higher precision of the 2 values
          //and then "raise" the other value up to it
          ...     
       }
    
       public int Precision { get; private set; }
       public decimal Value { get; private set; }
    }

    So now you can work with values that that their "units" with them.

    var yen = new Pip(110.00, 2);
    var pound = new Pip(1.2550, 4);
    
    //Result would be added value with precision of 4
    var whateverThisIs = yen.Add(pound);
    Of course the functionality you add will depend upon what behavior you need but a wrapper type makes it easy to track all this data. There are other ways to solve this problem as well but this is probably how I'd do it.

    Thursday, March 30, 2017 10:02 PM
    Moderator
  • Oh boy! You're moving a bit outside my understanding of programming there, but I'll read through this a few times and experiment with it.

    Thanks!

    Re

    Dennis

    Thursday, March 30, 2017 10:08 PM
  • No the numbers can vary, but in this case I'm only interested in those two options.

    In any case, I converted the decimal to a string setting the precision using the UsePoint variable, and then using a "Right function". I works.

    Re

    D

    Friday, March 31, 2017 7:30 PM