When is it safe to assume a double is zero - double

I'm programming this symbolic math program, and I'm questioning the way I detect a zero constant, for example to check if it should return a sum or just a single object.
Right now I'm checking if (-Double.MIN_NORMAL <= constantPart.evaluate() && constantPart.evaluate() <= Double.MIN_NORMAL), although I'm not sure this margin is sufficient.
Is it bad to rely on the gradual underflow to produce a denormalized value less than Double.MIN_NORMAL? What should the error margin be otherwise.
Would for example 2 * Double.MIN_NORMAL suffice?
I could obviously do some testing, but I feel like that wouldn't quite inform me of what's happening inside.
Is there a way to determine a sufficient margin for any specific case?

Related

Display an Error message when signal is less than a value in Simulink

I want to display an Error message when the signal reaches a certain value or simply when it reaches 0 I've used the ifblock and Relational Operatorbut it does not work for me.
You're most likely checking if the signal is exactly zero, which with floating point arithmetic is almost always a very bad thing to do.
Rather, you want to check that the absolute value of the signal is less than some small tolerance. More than that, you almost certainly need to check if the average of the signal over the past n-time points (where you choose n) is less than the tolerance.
You might also consider using something like the Static Gap block from the Model Verification library.

Underflow in Matlab

Is it a good practice to manually set numbers with large negative exponential like 1e-300 to zero to avoid underflow in Matlab?
If not how can we avoid harm of underflow when implementing functions like log(1+exp(x))?
Typically, you get trouble when adding very large and very small values, because this can lead to a high relative error. Get rid of this summation (1+exp(x)), it quickly runs out of the range of double values when x is large.
log(1+exp(x))
log(1+1/exp(x))*exp(x))
log(1+1/exp(x))+log(exp(x))
log(1+1/exp(x))+x
An alternative is the use of vpa:
log(1+exp(vpa(10^6)))
very slow, but you get a result with the configured precision.
I never saw a case where manually setting small values to zero was a good solution, typically comparing with a tolerance is better.

Getting around floating point error with logarithms?

I'm trying to write a basic digit counter (an integer is inputted and the number of digits of that integer is outputted) for positive integers. This is my general formula:
dig(x) := Math.floor(Math.log(x,10))
I tried implementing the equivalent of dig(x) in Ruby, and found that when I was computing dig(1000) I was getting 2 instead of 3 because Math.log was returning 2.9999999999999996 which would then be truncated down to 2. What is the proper way to handle this problem? (I'm assuming this problem can occur regardless of the language used to implement this approach, but if that's not the case then please explain that in your answer).
To get an exact count of the number of digits in an integer, you can do the usual thing: (in C/C++, assuming n is non-negative)
int digits = 0;
while (n > 0) {
n = n / 10; // integer division, just drops the ones digit and shifts right
digits = digits + 1;
}
I'm not certain but I suspect running a built-in logarithm function won't be faster than this, and this will give you an exact answer.
I thought about it for a minute and couldn't come up with a way to make the logarithm-based approach work with any guarantees, and almost convinced myself that it is probably a doomed pursuit in the first place because of floating point rounding errors, etc.
From The Art of Computer Programming volume 2, we will eliminate one bit of error before the floor function is applied by adding that one bit back in.
Let x be the result of log and then do x += x / 0x10000000 for a single precision floating point number (C's float). Then pass the value into floor.
This is guaranteed to be the fastest (assuming you have the answer in numerical form) because it uses only a few floating point instructions.
Floating point is always subject to roundoff error; that's one of the hazards you need to be aware of, and actively manage, when working with it. The proper way to handle it, if you must use floats is to figure out what the expected amount of accumulated error is and allow for that in comparisons and printouts -- round off appropriately, compare for whether the difference is within that range rather than comparing for equality, etcetera.
There is no exact binary-floating-point representation of simple things like 1/10th, for example.
(As others have noted, you could rewrite the problem to avoid using the floating-point-based solution entirely, but since you asked specifically about working log() I wanted to address that question; apologies if I'm off target. Some of the other answers provide specific suggestions for how you might round off the result. That would "solve" this particular case, but as your floating operations get more complicated you'll have to continue to allow for roundoff accumulating at each step and either deal with the error at each step or deal with the cumulative error -- the latter being the more complicated but more accurate solution.)
If this is a serious problem for an application, folks sometimes use scaled fixed point instead (running financial computations in terms of pennies rather than dollars, for example). Or they use one of the "big number" packages which computes in decimal rather than in binary; those have their own round-off problems, but they round off more the way humans expect them to.

Simple algorithm modeling stock market behavior

I have been working on a virtual stock market game using PHP. The formula that I have been using for deciding the price of a stock is
$price += $ran*0.001*$price + $ratio*0.005*$price
where
$ran = rand(-1*$intensity, 2*$intensity)
$intensity is a number between -5 to 5 depending upon whether the news is good or bad for the company and
$ratio = (1.0*($buy-$sell))/($buy + $sell)
$buy and $sell represent the number of shares bought and sold of a company respectively.
The problem with this formula is that, even if the intensity is negative (even -5) the ratio term is always added to the price which makes the overall term increase. The prices are refreshed every 10 seconds and with the above formula they keep on increasing and never come down. So, can anyone help me out with this formula so that it varies more closely to the actual stock market?
If I understand correctly, you're trying to define an algorithm to determine a logical next price based on the current price, some market activity, and a random input. This is called a Random Walk, and the linked page is quite informative.
In economics, the "random walk hypothesis" is used to model shares prices and other factors. Empirical studies found some deviations from this theoretical model, especially in short term and long term correlations.
It's difficult for us to provide an exact function for you, since the exact behavior you expect of a function like this is inherently application specific. However it is possible to test the behavior and improve on it, by pulling it out into its own method and tweaking it until you see the behavior you want.
I would suggest pulling this behavior you've defined into an SSCCE (or a unit test, but assuming you don't already have a PHP unit test framework set up, an example will do fine) and creating some test cases, then you can tweak your algorithm in a vacuum and find behavior you like.
Here's some boilerplate to get started:
<?php
function nextPrice($price, $intensity, $buy, $sell, $rand) {
// TODO
}
// Can tweak these values between runs, or put them in a loop if you want
$testPrice = 10.0;
$testBuy = 10000;
$testSell = 10000;
for ($i = -5; $i <= 5; $i++) {
// random float, from http://stackoverflow.com/a/14155720/113632
// set to a constant if you want to isolate the randomness and test other variables
$testRand = mt_rand(0, mt_getrandmax() - 1) / mt_getrandmax();
echo "<p>Intensity: $i - Rand: $testRand = ".
nextPrice($testPrice, $i, $testBuy, $testSell, $testRand)."</p>";
}
?>
Some additional thoughts:
Your $ran definition is definitely flawed, if $intensity is -5 you're executing $ran = rand(5, -10); which generates a warning and doesn't return the value you want. This is likely the root of your issue, as any negative $intensity will essentially set $ran to zero.
Furthermore your $ran definition is biased towards positive numbers, meaning the price is - rather quickly - going to rise even if there's bad news. I'd suggest ensuring your random value is equally likely to lower the stock as raise it, and if you intend for the stock to rise in value over time regardless (which seems like a bad idea to me) set a separate $longTermGrowthFactor that always increases the stock by that factor, separately from the randomness.
Turn on warning reporting in PHP - since you presumably hadn't seen the warnings related to your rand() call, you likely have warnings and other error types turned off, which quite likely means there are other errors hidden in your code you aren't aware of, and without the reporting they're going to be hard to spot.
Use mt_rand() instead of rand(), the latter is deprecated, and mt_rand() is a drop-in replacement providing better randomness.

iOS -- implementing complex numbers

As a follow-up to this question:
I was in the process of implementing a calculator app using Apple's complex number support when I noticed that if one calculates using that support, one ends up with the following:
(1+i)^2=1.2246063538223773e-16 + 2i
Of course the correct identity is (1+i)^2=2i. This is a specific example of a more general phenomenon -- roundoff errors can be really annoying if they round a part that is supposed to be zero to something that is slightly nonzero.
Suggestions on how to deal with this? I could implement integer powers of complex numbers in other ways, but the general problem will remain, and my solution could itself cause other inconsistencies.
As you note, this is as standard rounding error issue with floating points. A #Howard notes, you should likely round your double results back into the float range before displaying.
I typically use FLT_EPSILON to help me with these kinds of things as well.
#define fequal(a,b) (fabs((a) - (b)) < FLT_EPSILON)
#define fequalzero(a) (fabs(a) < FLT_EPSILON)
With those, you might like a function like this (untested)
inline void froundzero(a) { if (fequalzero(a)) a = 0; }
The complex version is left as an exercise for the reader as they say :D