float/double Math.Round in C#
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(ff, 1, MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
frst: 31.1
drst: 31.2
Can someone explain why?
c# rounding
|
show 4 more comments
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(ff, 1, MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
frst: 31.1
drst: 31.2
Can someone explain why?
c# rounding
2
Because(float)31.15
is not equal to(double)31.15
. Floating-point-arithmetic allmost allways yields to rounding-erros. In paticular rounding a double works different from rounding a float.
– HimBromBeere
2 hours ago
1
Rounding errors are unavoidable with floating point values. They are as unavoidable as death and taxes : youtube.com/watch?v=PZRI1IfStY0
– Christopher
1 hour ago
1
Possible duplicate of Difference between decimal, float and double in .NET?
– Jan S.
1 hour ago
3
@i486 Well, not always, there is a reason whyfloat
exists.
– SeM
1 hour ago
2
@i486 Again, that doesn't mean, that you should never usefloat
.
– SeM
56 mins ago
|
show 4 more comments
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(ff, 1, MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
frst: 31.1
drst: 31.2
Can someone explain why?
c# rounding
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(ff, 1, MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
frst: 31.1
drst: 31.2
Can someone explain why?
c# rounding
c# rounding
edited 1 hour ago
Dmitry Bychenko
107k1092133
107k1092133
asked 2 hours ago
YaoqingYaoqing
902
902
2
Because(float)31.15
is not equal to(double)31.15
. Floating-point-arithmetic allmost allways yields to rounding-erros. In paticular rounding a double works different from rounding a float.
– HimBromBeere
2 hours ago
1
Rounding errors are unavoidable with floating point values. They are as unavoidable as death and taxes : youtube.com/watch?v=PZRI1IfStY0
– Christopher
1 hour ago
1
Possible duplicate of Difference between decimal, float and double in .NET?
– Jan S.
1 hour ago
3
@i486 Well, not always, there is a reason whyfloat
exists.
– SeM
1 hour ago
2
@i486 Again, that doesn't mean, that you should never usefloat
.
– SeM
56 mins ago
|
show 4 more comments
2
Because(float)31.15
is not equal to(double)31.15
. Floating-point-arithmetic allmost allways yields to rounding-erros. In paticular rounding a double works different from rounding a float.
– HimBromBeere
2 hours ago
1
Rounding errors are unavoidable with floating point values. They are as unavoidable as death and taxes : youtube.com/watch?v=PZRI1IfStY0
– Christopher
1 hour ago
1
Possible duplicate of Difference between decimal, float and double in .NET?
– Jan S.
1 hour ago
3
@i486 Well, not always, there is a reason whyfloat
exists.
– SeM
1 hour ago
2
@i486 Again, that doesn't mean, that you should never usefloat
.
– SeM
56 mins ago
2
2
Because
(float)31.15
is not equal to (double)31.15
. Floating-point-arithmetic allmost allways yields to rounding-erros. In paticular rounding a double works different from rounding a float.– HimBromBeere
2 hours ago
Because
(float)31.15
is not equal to (double)31.15
. Floating-point-arithmetic allmost allways yields to rounding-erros. In paticular rounding a double works different from rounding a float.– HimBromBeere
2 hours ago
1
1
Rounding errors are unavoidable with floating point values. They are as unavoidable as death and taxes : youtube.com/watch?v=PZRI1IfStY0
– Christopher
1 hour ago
Rounding errors are unavoidable with floating point values. They are as unavoidable as death and taxes : youtube.com/watch?v=PZRI1IfStY0
– Christopher
1 hour ago
1
1
Possible duplicate of Difference between decimal, float and double in .NET?
– Jan S.
1 hour ago
Possible duplicate of Difference between decimal, float and double in .NET?
– Jan S.
1 hour ago
3
3
@i486 Well, not always, there is a reason why
float
exists.– SeM
1 hour ago
@i486 Well, not always, there is a reason why
float
exists.– SeM
1 hour ago
2
2
@i486 Again, that doesn't mean, that you should never use
float
.– SeM
56 mins ago
@i486 Again, that doesn't mean, that you should never use
float
.– SeM
56 mins ago
|
show 4 more comments
3 Answers
3
active
oldest
votes
Well, Math.Round
wants double
, not float
, that's why
Math.Round(ff, 1, MidpointRounding.AwayFromZero);
equals to
Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);
and if we inspect (double)ff
value
Console.Write(((double)ff).ToString("R"));
we'll see round up errors in action
31.149999618530273
Finally, Math.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1
as expected
I'm curious why(double)ff
is exactly31.14999961853027
and not31.150000000000000
– Gonzalo Lorieto
1 hour ago
4
@Gonzalo Lorieto:double
is binary and0.15 == 15 / 100 = 3 / 20
is a periodic fraction in binary representation.
– Dmitry Bychenko
1 hour ago
1
@GonzaloLorieto stackoverflow.com/questions/618535/…
– Camilo Terevinto
1 hour ago
1
@GonzaloLorieto You can read it here -> Floating-point arithmetic
– SeM
1 hour ago
add a comment |
In floating point, all numbers are represented internally as fractions where the denominator is a power of 2.
(This is a similar way to how decimals are actually fractions with power-of-10 denominators. So 31.15
is just a way of writing the fraction 3115/100
)
In floating point, 31.15
must be represented internally as a binary number. The closest binary fraction is: 1111.1001001100110011001100110011001100110011001100110011001100...repeating
The 1100
recurs (repeats forever), and so the number will be truncated depending on whether it is stored in a double or a float. In a float it is truncated to 24 digits, and in a double to 53.
Exact: 1111.100100110011001100110011001100110011001100110011001100110011001100...forever
Float: 1111.10010011001100110011
Double: 1111.1001001100110011001100110011001100110011001100110
Therefore you can see that the double that this number converts to, is actually slightly larger than the float it converts to. So it is clear that it won't necessarily round to the same number, since it is not the same number to begin with.
add a comment |
It is already explained why we do have that rounding problem but it is worth mentioning that with this small trick you can get away from it:
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(
double.Parse(ff.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
1,
MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
Then the result should be the same:
3.2
3.2
so while (double)ff
introduce rounding problem, double.Parse(ff.ToString())
doesn't because the conversion from float
to double
is avoided.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54235885%2ffloat-double-math-round-in-c-sharp%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Well, Math.Round
wants double
, not float
, that's why
Math.Round(ff, 1, MidpointRounding.AwayFromZero);
equals to
Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);
and if we inspect (double)ff
value
Console.Write(((double)ff).ToString("R"));
we'll see round up errors in action
31.149999618530273
Finally, Math.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1
as expected
I'm curious why(double)ff
is exactly31.14999961853027
and not31.150000000000000
– Gonzalo Lorieto
1 hour ago
4
@Gonzalo Lorieto:double
is binary and0.15 == 15 / 100 = 3 / 20
is a periodic fraction in binary representation.
– Dmitry Bychenko
1 hour ago
1
@GonzaloLorieto stackoverflow.com/questions/618535/…
– Camilo Terevinto
1 hour ago
1
@GonzaloLorieto You can read it here -> Floating-point arithmetic
– SeM
1 hour ago
add a comment |
Well, Math.Round
wants double
, not float
, that's why
Math.Round(ff, 1, MidpointRounding.AwayFromZero);
equals to
Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);
and if we inspect (double)ff
value
Console.Write(((double)ff).ToString("R"));
we'll see round up errors in action
31.149999618530273
Finally, Math.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1
as expected
I'm curious why(double)ff
is exactly31.14999961853027
and not31.150000000000000
– Gonzalo Lorieto
1 hour ago
4
@Gonzalo Lorieto:double
is binary and0.15 == 15 / 100 = 3 / 20
is a periodic fraction in binary representation.
– Dmitry Bychenko
1 hour ago
1
@GonzaloLorieto stackoverflow.com/questions/618535/…
– Camilo Terevinto
1 hour ago
1
@GonzaloLorieto You can read it here -> Floating-point arithmetic
– SeM
1 hour ago
add a comment |
Well, Math.Round
wants double
, not float
, that's why
Math.Round(ff, 1, MidpointRounding.AwayFromZero);
equals to
Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);
and if we inspect (double)ff
value
Console.Write(((double)ff).ToString("R"));
we'll see round up errors in action
31.149999618530273
Finally, Math.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1
as expected
Well, Math.Round
wants double
, not float
, that's why
Math.Round(ff, 1, MidpointRounding.AwayFromZero);
equals to
Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);
and if we inspect (double)ff
value
Console.Write(((double)ff).ToString("R"));
we'll see round up errors in action
31.149999618530273
Finally, Math.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1
as expected
answered 1 hour ago
Dmitry BychenkoDmitry Bychenko
107k1092133
107k1092133
I'm curious why(double)ff
is exactly31.14999961853027
and not31.150000000000000
– Gonzalo Lorieto
1 hour ago
4
@Gonzalo Lorieto:double
is binary and0.15 == 15 / 100 = 3 / 20
is a periodic fraction in binary representation.
– Dmitry Bychenko
1 hour ago
1
@GonzaloLorieto stackoverflow.com/questions/618535/…
– Camilo Terevinto
1 hour ago
1
@GonzaloLorieto You can read it here -> Floating-point arithmetic
– SeM
1 hour ago
add a comment |
I'm curious why(double)ff
is exactly31.14999961853027
and not31.150000000000000
– Gonzalo Lorieto
1 hour ago
4
@Gonzalo Lorieto:double
is binary and0.15 == 15 / 100 = 3 / 20
is a periodic fraction in binary representation.
– Dmitry Bychenko
1 hour ago
1
@GonzaloLorieto stackoverflow.com/questions/618535/…
– Camilo Terevinto
1 hour ago
1
@GonzaloLorieto You can read it here -> Floating-point arithmetic
– SeM
1 hour ago
I'm curious why
(double)ff
is exactly 31.14999961853027
and not 31.150000000000000
– Gonzalo Lorieto
1 hour ago
I'm curious why
(double)ff
is exactly 31.14999961853027
and not 31.150000000000000
– Gonzalo Lorieto
1 hour ago
4
4
@Gonzalo Lorieto:
double
is binary and 0.15 == 15 / 100 = 3 / 20
is a periodic fraction in binary representation.– Dmitry Bychenko
1 hour ago
@Gonzalo Lorieto:
double
is binary and 0.15 == 15 / 100 = 3 / 20
is a periodic fraction in binary representation.– Dmitry Bychenko
1 hour ago
1
1
@GonzaloLorieto stackoverflow.com/questions/618535/…
– Camilo Terevinto
1 hour ago
@GonzaloLorieto stackoverflow.com/questions/618535/…
– Camilo Terevinto
1 hour ago
1
1
@GonzaloLorieto You can read it here -> Floating-point arithmetic
– SeM
1 hour ago
@GonzaloLorieto You can read it here -> Floating-point arithmetic
– SeM
1 hour ago
add a comment |
In floating point, all numbers are represented internally as fractions where the denominator is a power of 2.
(This is a similar way to how decimals are actually fractions with power-of-10 denominators. So 31.15
is just a way of writing the fraction 3115/100
)
In floating point, 31.15
must be represented internally as a binary number. The closest binary fraction is: 1111.1001001100110011001100110011001100110011001100110011001100...repeating
The 1100
recurs (repeats forever), and so the number will be truncated depending on whether it is stored in a double or a float. In a float it is truncated to 24 digits, and in a double to 53.
Exact: 1111.100100110011001100110011001100110011001100110011001100110011001100...forever
Float: 1111.10010011001100110011
Double: 1111.1001001100110011001100110011001100110011001100110
Therefore you can see that the double that this number converts to, is actually slightly larger than the float it converts to. So it is clear that it won't necessarily round to the same number, since it is not the same number to begin with.
add a comment |
In floating point, all numbers are represented internally as fractions where the denominator is a power of 2.
(This is a similar way to how decimals are actually fractions with power-of-10 denominators. So 31.15
is just a way of writing the fraction 3115/100
)
In floating point, 31.15
must be represented internally as a binary number. The closest binary fraction is: 1111.1001001100110011001100110011001100110011001100110011001100...repeating
The 1100
recurs (repeats forever), and so the number will be truncated depending on whether it is stored in a double or a float. In a float it is truncated to 24 digits, and in a double to 53.
Exact: 1111.100100110011001100110011001100110011001100110011001100110011001100...forever
Float: 1111.10010011001100110011
Double: 1111.1001001100110011001100110011001100110011001100110
Therefore you can see that the double that this number converts to, is actually slightly larger than the float it converts to. So it is clear that it won't necessarily round to the same number, since it is not the same number to begin with.
add a comment |
In floating point, all numbers are represented internally as fractions where the denominator is a power of 2.
(This is a similar way to how decimals are actually fractions with power-of-10 denominators. So 31.15
is just a way of writing the fraction 3115/100
)
In floating point, 31.15
must be represented internally as a binary number. The closest binary fraction is: 1111.1001001100110011001100110011001100110011001100110011001100...repeating
The 1100
recurs (repeats forever), and so the number will be truncated depending on whether it is stored in a double or a float. In a float it is truncated to 24 digits, and in a double to 53.
Exact: 1111.100100110011001100110011001100110011001100110011001100110011001100...forever
Float: 1111.10010011001100110011
Double: 1111.1001001100110011001100110011001100110011001100110
Therefore you can see that the double that this number converts to, is actually slightly larger than the float it converts to. So it is clear that it won't necessarily round to the same number, since it is not the same number to begin with.
In floating point, all numbers are represented internally as fractions where the denominator is a power of 2.
(This is a similar way to how decimals are actually fractions with power-of-10 denominators. So 31.15
is just a way of writing the fraction 3115/100
)
In floating point, 31.15
must be represented internally as a binary number. The closest binary fraction is: 1111.1001001100110011001100110011001100110011001100110011001100...repeating
The 1100
recurs (repeats forever), and so the number will be truncated depending on whether it is stored in a double or a float. In a float it is truncated to 24 digits, and in a double to 53.
Exact: 1111.100100110011001100110011001100110011001100110011001100110011001100...forever
Float: 1111.10010011001100110011
Double: 1111.1001001100110011001100110011001100110011001100110
Therefore you can see that the double that this number converts to, is actually slightly larger than the float it converts to. So it is clear that it won't necessarily round to the same number, since it is not the same number to begin with.
edited 1 hour ago
answered 1 hour ago
BenBen
28.7k55487
28.7k55487
add a comment |
add a comment |
It is already explained why we do have that rounding problem but it is worth mentioning that with this small trick you can get away from it:
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(
double.Parse(ff.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
1,
MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
Then the result should be the same:
3.2
3.2
so while (double)ff
introduce rounding problem, double.Parse(ff.ToString())
doesn't because the conversion from float
to double
is avoided.
add a comment |
It is already explained why we do have that rounding problem but it is worth mentioning that with this small trick you can get away from it:
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(
double.Parse(ff.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
1,
MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
Then the result should be the same:
3.2
3.2
so while (double)ff
introduce rounding problem, double.Parse(ff.ToString())
doesn't because the conversion from float
to double
is avoided.
add a comment |
It is already explained why we do have that rounding problem but it is worth mentioning that with this small trick you can get away from it:
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(
double.Parse(ff.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
1,
MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
Then the result should be the same:
3.2
3.2
so while (double)ff
introduce rounding problem, double.Parse(ff.ToString())
doesn't because the conversion from float
to double
is avoided.
It is already explained why we do have that rounding problem but it is worth mentioning that with this small trick you can get away from it:
float ff = (float)31.15;
double dd = 31.15;
var frst = Math.Round(
double.Parse(ff.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
1,
MidpointRounding.AwayFromZero);
var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);
Then the result should be the same:
3.2
3.2
so while (double)ff
introduce rounding problem, double.Parse(ff.ToString())
doesn't because the conversion from float
to double
is avoided.
edited 1 min ago
answered 1 hour ago
JohnnyJohnny
1,704615
1,704615
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54235885%2ffloat-double-math-round-in-c-sharp%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Because
(float)31.15
is not equal to(double)31.15
. Floating-point-arithmetic allmost allways yields to rounding-erros. In paticular rounding a double works different from rounding a float.– HimBromBeere
2 hours ago
1
Rounding errors are unavoidable with floating point values. They are as unavoidable as death and taxes : youtube.com/watch?v=PZRI1IfStY0
– Christopher
1 hour ago
1
Possible duplicate of Difference between decimal, float and double in .NET?
– Jan S.
1 hour ago
3
@i486 Well, not always, there is a reason why
float
exists.– SeM
1 hour ago
2
@i486 Again, that doesn't mean, that you should never use
float
.– SeM
56 mins ago