Reputation: 36048
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?
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
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
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