Consider the following C++ code:
double someZero = 0;
std::cout << 0 - someZero << '\n'; // prints 0
std::cout << -someZero << std::endl; // prints -0
The question arises: what is negative zero good for, and should it be defensively avoided (i.e. use subtraction instead of smacking a minus onto a variable)?
From Wikipedia:
It is claimed that the inclusion of signed zero in IEEE 754 makes it much easier to achieve numerical accuracy in some critical problems[1], in particular when computing with complex elementary functions[2].
The first reference is "Branch Cuts for Complex Elementary Functions or Much Ado About Nothing's Sign Bit" by W. Kahan, that is available for download here.
One example from that paper is 1/(+0) vs 1/(-0). Here, the sign of zero makes a huge difference, since the first expression equals +inf and the second, -inf.
In addition
Signed Zero Good For :
The zeroes can be considered as a variant of the extended real number line such that 1/−0 = −∞ and 1/+0 = +∞, division by zero is only undefined for ±0/±0.
Negatively signed zero echoes the mathematical analysis concept of approaching 0 from below as a one-sided limit, which may be denoted by x → 0−, x → 0−, or x → ↑0. The notation "−0" may be used informally to denote a small negative number that has been rounded to zero. The concept of negative zero also has some theoretical applications in statistical mechanics and other disciplines
There are only two real use-cases that I can see:
You want to show that a value is negative but very very small (perhaps infinitessimal), i.e. too small to represent as a float or double.
You are working with math that only allows negatives, but still want to display zero. There are a few cases in physics, complex numbers and number theory where this can be useful.
For the mostpart, it's not useful and should be avoided.
You may also want to take a look at this question: Is there a negative zero? and the IEEE 754 spec for floating point.
I'm making a measuring app, and the -0 is very useful for mixed numbers (such as separating into feet and inches).
Imagine that we have a variable "length" that we're trying to separate into "feet" and "inches".
(This is java code, but the same idea is true for C++).
feet = Math.signum(length) * Math.floor(Math.abs(length / 12));
// could also do feet = length>0 ? Math.floor(length / 12) : Math.ceil(length / 12)
inches = Math.abs(length) % 12;
If the length is between -1 feet and 0 feet, we'd want it to say -0 for the feet so we know it's negative.
Negative zero has for example some use when handling complex numbers...
In everyday use one should mostly avoid the negative zero.
Some links with information regarding background/uses/pitfalls of "negative zero":
http://en.wikipedia.org/wiki/Signed_zero
http://en.wikipedia.org/wiki/Floating_point#Signed_zero
http://en.wikipedia.org/wiki/Branch_cut
http://connect.microsoft.com/VisualStudio/feedback/details/344366/negative-zero-behavior-between-c-and-c-code-is-different
http://connect.microsoft.com/VisualStudio/feedback/details/292276/in-vs2005-c-zero-reported-as-negative-zero-for-double-type
C++ ceil and negative zero
Related
Consider the following C++ code:
double someZero = 0;
std::cout << 0 - someZero << '\n'; // prints 0
std::cout << -someZero << std::endl; // prints -0
The question arises: what is negative zero good for, and should it be defensively avoided (i.e. use subtraction instead of smacking a minus onto a variable)?
From Wikipedia:
It is claimed that the inclusion of signed zero in IEEE 754 makes it much easier to achieve numerical accuracy in some critical problems[1], in particular when computing with complex elementary functions[2].
The first reference is "Branch Cuts for Complex Elementary Functions or Much Ado About Nothing's Sign Bit" by W. Kahan, that is available for download here.
One example from that paper is 1/(+0) vs 1/(-0). Here, the sign of zero makes a huge difference, since the first expression equals +inf and the second, -inf.
In addition
Signed Zero Good For :
The zeroes can be considered as a variant of the extended real number line such that 1/−0 = −∞ and 1/+0 = +∞, division by zero is only undefined for ±0/±0.
Negatively signed zero echoes the mathematical analysis concept of approaching 0 from below as a one-sided limit, which may be denoted by x → 0−, x → 0−, or x → ↑0. The notation "−0" may be used informally to denote a small negative number that has been rounded to zero. The concept of negative zero also has some theoretical applications in statistical mechanics and other disciplines
There are only two real use-cases that I can see:
You want to show that a value is negative but very very small (perhaps infinitessimal), i.e. too small to represent as a float or double.
You are working with math that only allows negatives, but still want to display zero. There are a few cases in physics, complex numbers and number theory where this can be useful.
For the mostpart, it's not useful and should be avoided.
You may also want to take a look at this question: Is there a negative zero? and the IEEE 754 spec for floating point.
I'm making a measuring app, and the -0 is very useful for mixed numbers (such as separating into feet and inches).
Imagine that we have a variable "length" that we're trying to separate into "feet" and "inches".
(This is java code, but the same idea is true for C++).
feet = Math.signum(length) * Math.floor(Math.abs(length / 12));
// could also do feet = length>0 ? Math.floor(length / 12) : Math.ceil(length / 12)
inches = Math.abs(length) % 12;
If the length is between -1 feet and 0 feet, we'd want it to say -0 for the feet so we know it's negative.
Negative zero has for example some use when handling complex numbers...
In everyday use one should mostly avoid the negative zero.
Some links with information regarding background/uses/pitfalls of "negative zero":
http://en.wikipedia.org/wiki/Signed_zero
http://en.wikipedia.org/wiki/Floating_point#Signed_zero
http://en.wikipedia.org/wiki/Branch_cut
http://connect.microsoft.com/VisualStudio/feedback/details/344366/negative-zero-behavior-between-c-and-c-code-is-different
http://connect.microsoft.com/VisualStudio/feedback/details/292276/in-vs2005-c-zero-reported-as-negative-zero-for-double-type
C++ ceil and negative zero
Due to the floating point "approx" nature, its possible that two different sets of values return the same value.
Example:
#include <iostream>
int main() {
std::cout.precision(100);
double a = 0.5;
double b = 0.5;
double c = 0.49999999999999994;
std::cout << a + b << std::endl; // output "exact" 1.0
std::cout << a + c << std::endl; // output "exact" 1.0
}
But is it also possible with subtraction? I mean: is there two sets of different values (keeping one value of them) that return 0.0?
i.e. a - b = 0.0 and a - c = 0.0, given some sets of a,b and a,c with b != c??
The IEEE-754 standard was deliberately designed so that subtracting two values produces zero if and only if the two values are equal, except that subtracting an infinity from itself produces NaN and/or an exception.
Unfortunately, C++ does not require conformance to IEEE-754, and many C++ implementations use some features of IEEE-754 but do not fully conform.
A not uncommon behavior is to “flush” subnormal results to zero. This is part of a hardware design to avoid the burden of handling subnormal results correctly. If this behavior is in effect, the subtraction of two very small but different numbers can yield zero. (The numbers would have to be near the bottom of the normal range, having some significand bits in the subnormal range.)
Sometimes systems with this behavior may offer a way of disabling it.
Another behavior to beware of is that C++ does not require floating-point operations to be carried out precisely as written. It allows “excess precision” to be used in intermediate operations and “contractions” of some expressions. For example, a*b - c*d may be computed by using one operation that multiplies a and b and then another that multiplies c and d and subtracts the result from the previously computed a*b. This latter operation acts as if c*d were computed with infinite precision rather than rounded to the nominal floating-point format. In this case, a*b - c*d may produce a non-zero result even though a*b == c*d evaluates to true.
Some C++ implementations offer ways to disable or limit such behavior.
Gradual underflow feature of IEEE floating point standard prevents this. Gradual underflow is achieved by subnormal (denormal) numbers, which are spaced evenly (as opposed to logarithmically, like normal floating point) and located between the smallest negative and positive normal numbers with zeroes in the middle. As they are evenly spaced, the addition of two subnormal numbers of differing signedness (i.e. subtraction towards zero) is exact and therefore won't reproduce what you ask. The smallest subnormal is (much) less than the smallest distance between normal numbers, and therefore any subtraction between unequal normal numbers is going to be closer to a subnormal than zero.
If you disable IEEE conformance using a special denormals-are-zero (DAZ) or flush-to-zero (FTZ) mode of the CPU, then indeed you could subtract two small, close numbers which would otherwise result in a subnormal number, which would be treated as zero due to the mode of the CPU. A working example (Linux):
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); // system specific
double d = std::numeric_limits<double>::min(); // smallest normal
double n = std::nextafter(d, 10.0); // second smallest normal
double z = d - n; // a negative subnormal (flushed to zero)
std::cout << (z == 0) << '\n' << (d == n);
This should print
1
0
First 1 indicates that result of subtraction is exactly zero, while the second 0 indicates that the operands are not equal.
Unfortunately the answer is dependent on your implementation and the way it is configured. C and C++ don't demand any specific floating point representation or behavior. Most implementations use the IEEE 754 representations, but they don't always precisely implement IEEE 754 arithmetic behaviour.
To understand the answer to this question we must first understand how floating point numbers work.
A naive floating point representation would have an exponent, a sign and a mantissa. It's value would be
(-1)s2(e – e0)(m/2M)
Where:
s is the sign bit, with a value of 0 or 1.
e is the exponent field
e0 is the exponent bias. It essentially sets the overall range of the floating point number.
M is the number of mantissa bits.
m is the mantissa with a value between 0 and 2M-1
This is similar in concept to the scientific notation you were taught in school.
However this format has many different representations of the same number, nearly a whole bit's worth of encoding space is wasted. To fix this we can add an "implicit 1" to the mantissa.
(-1)s2(e – e0)(1+(m/2M))
This format has exactly one representation of each number. However there is a problem with it, it can't represent zero or numbers close to zero.
To fix this IEEE floating point reserves a couple of exponent values for special cases. An exponent value of zero is reserved for representing small numbers known as subnormals. The highest possible exponent value is reserved for NaNs and infinities (which I will ignore in this post since they aren't relevant here). So the definition now becomes.
(-1)s2(1 – e0)(m/2M) when e = 0
(-1)s2(e – e0)(1+(m/2M)) when e >0 and e < 2E-1
With this representation smaller numbers always have a step size that is less than or equal to that for larger ones. So provided the result of the subtraction is smaller in magnitude than both operands it can be represented exactly. In particular results close to but not exactly zero can be represented exactly.
This does not apply if the result is larger in magnitude than one or both of the operands, for example subtracting a small value from a large value or subtracting two values of opposite signs. In those cases the result may be imprecise but it clearly can't be zero.
Unfortunately FPU designers cut corners. Rather than including the logic to handle subnormal numbers quickly and correctly they either did not support (non-zero) subnormals at all or provided slow support for subnormals and then gave the user the option to turn it on and off. If support for proper subnormal calculations is not present or is disabled and the number is too small to represent in normalized form then it will be "flushed to zero".
So in the real world under some systems and configurations subtracting two different very-small floating point numbers can result in a zero answer.
Excluding funny numbers like NAN, I don't think it's possible.
Let's say a and b are normal finite IEEE 754 floats, and |a - b| is less than or equal to both |a| and |b| (otherwise it's clearly not zero).
That means the exponent is <= both a's and b's, and so the absolute precision is at least as high, which makes the subtraction exactly representable. That means that if a - b == 0, then it is exactly zero, so a == b.
Consider the following C++ code:
double someZero = 0;
std::cout << 0 - someZero << '\n'; // prints 0
std::cout << -someZero << std::endl; // prints -0
The question arises: what is negative zero good for, and should it be defensively avoided (i.e. use subtraction instead of smacking a minus onto a variable)?
From Wikipedia:
It is claimed that the inclusion of signed zero in IEEE 754 makes it much easier to achieve numerical accuracy in some critical problems[1], in particular when computing with complex elementary functions[2].
The first reference is "Branch Cuts for Complex Elementary Functions or Much Ado About Nothing's Sign Bit" by W. Kahan, that is available for download here.
One example from that paper is 1/(+0) vs 1/(-0). Here, the sign of zero makes a huge difference, since the first expression equals +inf and the second, -inf.
In addition
Signed Zero Good For :
The zeroes can be considered as a variant of the extended real number line such that 1/−0 = −∞ and 1/+0 = +∞, division by zero is only undefined for ±0/±0.
Negatively signed zero echoes the mathematical analysis concept of approaching 0 from below as a one-sided limit, which may be denoted by x → 0−, x → 0−, or x → ↑0. The notation "−0" may be used informally to denote a small negative number that has been rounded to zero. The concept of negative zero also has some theoretical applications in statistical mechanics and other disciplines
There are only two real use-cases that I can see:
You want to show that a value is negative but very very small (perhaps infinitessimal), i.e. too small to represent as a float or double.
You are working with math that only allows negatives, but still want to display zero. There are a few cases in physics, complex numbers and number theory where this can be useful.
For the mostpart, it's not useful and should be avoided.
You may also want to take a look at this question: Is there a negative zero? and the IEEE 754 spec for floating point.
I'm making a measuring app, and the -0 is very useful for mixed numbers (such as separating into feet and inches).
Imagine that we have a variable "length" that we're trying to separate into "feet" and "inches".
(This is java code, but the same idea is true for C++).
feet = Math.signum(length) * Math.floor(Math.abs(length / 12));
// could also do feet = length>0 ? Math.floor(length / 12) : Math.ceil(length / 12)
inches = Math.abs(length) % 12;
If the length is between -1 feet and 0 feet, we'd want it to say -0 for the feet so we know it's negative.
Negative zero has for example some use when handling complex numbers...
In everyday use one should mostly avoid the negative zero.
Some links with information regarding background/uses/pitfalls of "negative zero":
http://en.wikipedia.org/wiki/Signed_zero
http://en.wikipedia.org/wiki/Floating_point#Signed_zero
http://en.wikipedia.org/wiki/Branch_cut
http://connect.microsoft.com/VisualStudio/feedback/details/344366/negative-zero-behavior-between-c-and-c-code-is-different
http://connect.microsoft.com/VisualStudio/feedback/details/292276/in-vs2005-c-zero-reported-as-negative-zero-for-double-type
C++ ceil and negative zero
I want to perform some calculations and I want the result correct up to some decimal places, say 12.
So I wrote a sample:
#define PI 3.1415926535897932384626433832795028841971693993751
double d, k, h;
k = 999999/(2*PI);
h = 999999;
d = PI*k*k*h;
printf("%.12f\n", d);
But it gives the output:
79577232813771760.000000000000
I even used setprecision(), but same answer rather in exponential form.
cout<<setprecision(12)<<d<<endl;
prints
7.95772328138e+16
Used long double also, but in vain.
Now is there any way other than storing the integer part and the fractional part separately in long long int types?
If so, what can be done to get the answer precisely?
A double has only about 16 decimal digits of precision. Everything after the decimal point would be nonsense. (In fact, the last digit or two left of the point may not agree with an infinite-precision calculation.)
Long double is not standardized, AFAIK. It may be that on your system it is the same as double, or no more precise. That would slightly surprise me, but it doesn't violate anything.
You need to read Double-Precision concepts again; more carefully.
The double has increased precision by using 64 bits.
Stuff before the decimal is more important than that after it.
So, when you have a large integer part, it will truncate the lower precision -- this is being described to you in various answers here as rounding off.
Update:
To increase precision, you'll need to use some library or change your language.
Check this other question: Best coding language for dealing with large numbers (50000+ digits)
Yet, I'll ask you to re-check your intent once more.
Do you really need 12 decimal places for numbers that have really high values
(over 10 digits in the integer part like in your example)?
Maybe you won't really have large integer parts
(in which case such code should work fine).
But if you are tracking a value like 10000000000.123456789,
I am really interested in exactly which application you are working on (astronomy?).
If the integer part of your values is some way under 10000, you should be fine here.
Update2:
IF you must demonstrate the ability of a specific formula to work accurately within constrained error limits, the way to go is fixing the processing of your formula such that the least error is introduced.
Example,
If you want to do say, (x * y) / z
it would be prudent to try something like max(x,y)/z * min(x,y)
rather than, the original form which may overflow after (x * y), loosing precision if that did not fit in the 16 decimals of double
If you had just 2 digit precision,
. 2-digit regular-precision
`42 * 7 290 297
(42 * 7)/2 290/2 294/2
Result ==> 145 147
But ==> 42/2 = 21
21 * 7 = 147
This is probably the intent of your contest.
The double-precision binary format used by most computers can only hold about 16 digits, after that you'll get rounding. See http://en.wikipedia.org/wiki/Double-precision_floating-point_format
Floating point values have a limit range of digits. Just because your "PI" value has six times as many digits as a double will support doesn't alter the way the hardware works.
A typical (IEEE754) double will produce approximately 15-16 decimal places. Whether that's 0.12345678901235, 1234567.8901235, 12345678901235 or 12345678901235000000000, or some other variation.
In other words, yes, if you calculate your calculation EXACTLY, you'll get lots of decimal places, because pi never ends. On a computer, you get about 15-16 digits, no matter what input values you use - all that changes is where in that sequence the decimal place sits. To get more, you need "big number support", such as the Gnu Multiprcession (GMP) library.
You're looking for std::fixed. That tells the ostream not to use exponential form.
cout << setprecision(12) << std::fixed << d << endl;
I wrote this code to overload the unary operator- on a matrix class:
const RegMatrix RegMatrix::operator-()const{
RegMatrix result(numRow,numCol);
int i,j;
for(i=0;i<numRow;++i)
for(j=0;j<numCol;++j){
result.setElement(i,j,(-_matrix[i][j]));
}
return result;
}
When i ran my program with debugger in visual studio, it showed me that when the operation is done on a double equals zero, it inserts the result matrix the number -0.00000.
Is it some weird VS-display feature, or is it something i should handle carefully?
Signed zero is zero with an associated
sign. In ordinary arithmetic, −0 = +0
= 0. However, in computing, some number representations allow for the
existence of two zeros, often denoted
by −0 (negative zero) and +0 (positive
zero). This occurs in some signed
number representations for integers,
and in most floating point number
representations. The number 0 is
usually encoded as +0, however it can
be represented by either +0 or −0.
The IEEE 754 standard for floating
point arithmetic (presently used by
most computers and programming
languages that support floating point
numbers) requires both +0 and −0. The
zeroes can be considered as a variant
of the extended real number line such
that 1/−0 = −∞ and 1/+0 = +∞, division
by zero is only undefined for ±0/±0.
Negatively signed zero echoes the
mathematical analysis concept of
approaching 0 from below as a
one-sided limit, which may be denoted
by x → 0−, x → 0−, or x → ↑0. The
notation "−0" may be used informally
to denote a small negative number that
has been rounded to zero. The concept
of negative zero also has some
theoretical applications in
statistical mechanics and other
disciplines.
It is claimed that the inclusion of
signed zero in IEEE 754 makes it much
easier to achieve numerical accuracy
in some critical problems,1 in
particular when computing with complex
elementary functions.[2] On the other
hand, the concept of signed zero runs
contrary to the general assumption
made in most mathematical fields (and
in most mathematics courses) that
negative zero is the same thing as
zero. Representations that allow
negative zero can be a source of
errors in programs, as software
developers do not realize (or may
forget) that, while the two zero
representations behave as equal under
numeric comparisons, they are
different bit patterns and yield
different results in some operations.
For more information see Signed Zero wiki page.
using double (IEEE754), there is defined positive and negative zero.
Well for doubles actually have different values for '0.0' and '-0.0' I think it makes perfect sense....
What different result did you expect?
As ereOn said, you've got a negative zero:
#include <stdio.h>
int main()
{
printf("%f\n", -0.0);
}
-0 and 0 are the same thing, and it is nothing to worry about. Floating point numbers have the capability to have both a positive and negative 0, for math reasons. But -0 is interpreted the same way as 0 in C/C++ arithmetic.