Tono Nam
Tono Nam

Reputation: 36048

Increment the nth digit of a float

I am creating a control where I need to increment or decrement the nth digit of a float number. For instance if I want to increment:

12.3456    I want to increment the thousand (5) to 6
     ^

then I will write 12.3466

It is simple to do it when the number is not large (few significant digits). Take for instance 223456.109f if I then want to increase the first 2 I will like to end up with 323456.109f = 323456.1 (c# rounds 323456.109 to 323456.1 so that it can fit in 32 bits) . What am I doing right now is adding 100000. The problem is that if I add 10000 to 223456.109f then that will give me 323456.125f which is not the same as 323456.1f.

How can I solve this problem. Do I have to convert it to a string then do the math with the string?

Edit

Thanks to your answer here is my method:

    /// <summary>
    /// Increments the nth digit of a float number
    /// </summary>
    /// <param name="floatToIncrement">The number we are incrementing such as 12.34E+20f </param>
    /// <param name="positionToIncrement"> See example inside method. </param>        
    /// <param name="incrementOrDecrement">If true it will increment if false it will decrement</param>
    /// <returns></returns>
    static float IncrementFloat(float floatToIncrement, short positionToIncrement, bool incrementOrDecrement=true)
    {
        /* Example:
           10.5678

           1 = positionToIncrement ->  2
           0 = positionToIncrement ->  1
           5 = positionToIncrement -> -1
           6 = positionToIncrement -> -2
           etc
         */

        if (positionToIncrement == 0)
            return floatToIncrement;

        var floatToIncrementAsString = floatToIncrement.ToString("R");

        // a float number may be 1.20E+20 let's match it so that we can remove the E+20
        var match = Regex.Match(floatToIncrementAsString, @"(\d[^E]+)(.*)"); 

        var decimalNum = decimal.Parse(match.Groups[1].Value);

        // if position is greater than 0 we increment the nth digit to the left of the '.'
        if(positionToIncrement>0)
        {
            var numToAdd = int.Parse("1".PadRight(positionToIncrement, '0'));
            if (incrementOrDecrement)
                decimalNum += numToAdd;
            else
                decimalNum -= numToAdd;
        }
        else // else we do the same but to the right of the '.'
        {
            var x = Math.Abs(positionToIncrement);
            var y = "1".PadRight(x+1, '0');
            var numToAdd = int.Parse(y);

            if (incrementOrDecrement)
                decimalNum += 1 / ((decimal)(numToAdd));
            else
                decimalNum -= 1 / ((decimal)(numToAdd));
        }

        var result = decimalNum + match.Groups[2].Value;

        return float.Parse(result);            
    }

Upvotes: 2

Views: 931

Answers (2)

Pratik Singhal
Pratik Singhal

Reputation: 6492

You can use decimal data type , it has 28-29 significant digits, so it can solve your problem.

Approximate Range

(-7.9 x 1028 to 7.9 x 1028) / (100 to 28)

Precision

28-29 significant digits

Compare with Float

Precision

7 significant digits.

When you have to avoid roundoff error, always use decimal.

decimal has more significant figures than the float, therefore it can be more precise- it also takes up slightly more memory. Other than certain math or physics-related algorithms, the double or float should do fine.

Upvotes: 1

MarcinJuraszek
MarcinJuraszek

Reputation: 125620

If you need precise value you shouldn't use float or double. Use decimal instead.

The Decimal value type is appropriate for financial calculations that require large numbers of significant integral and fractional digits and no round-off errors.

from Decimal Structure

Upvotes: 1

Related Questions