How do I round numbers in KDB? - kdb

It looks like I can hack floor and ceiling into a meta function for an arbitrary round, but is there a standard way to do:
round[3.1415;2] = 3.14
from the core functions?
Edit: This is problem I'm trying to solve:
I have unadjusted daily stock data, and I'm trying to identify splits and filter them out. It's further complicated by decimalisation artefacts (a split might not be perfectly 2:1 because prices have minimum tick sizes).

This is possible via the use of .Q.f, this does however return the output as a string.
Using this we can round 3.14159 to 2 decimal places like so:
q) .Q.f[2;] 3.14
"3.14"
q)round:{"F"$.Q.f[y]x}
q)round[3.1415;2]
3.14

There's no standard way because in kdb you shouldn't ever really need to round floats. What's the reason to round floats? If it's just for pretty-printing displays then you can use a method like Matthew suggests, but underlying kdb logic shouldn't need it.
If you must, you can use floor/ceiling as you've already figured out or you can use the built-in nearest-rounding that casting to interger/long achieves. E.g.
q)d:{("j"$x*y)%x}
q)d2:d[100]
q)d3:d[1000]
q)
q)a:5?10.0
q)
q)d2 a
3.92 0.81 9.37 2.78 2.39
q)d3 a
3.915 0.812 9.368 2.782 2.392
But even here you should be aware that this is completely fictional rounding because you're still using floats and still subject to floating point fuzziness. If I increase the precision value those same results above are:
q)\P 18
q)
q)d2 a
3.9199999999999999 0.81000000000000005 9.3699999999999992 2.7799999999999998 ..
q)d3 a
3.915 0.81200000000000006 9.3680000000000003 2.782 2.3919999999999999
The only way to have a truly concrete number of decimal places is to store the whole numbers as ints/longs and separately store the decimals as ints/longs

Related

Are certain MATLAB functions only precise to a certain decimal? How precise is MATLAB really?

I am converting a program from MATLAB 2012 to 2016. I've been getting some strange errors, which I believe some of are due to a lack of precision in MATLAB functions.
For instance, I have a timeseries oldTs as such:
Time Data
-----------------------------
1.00000000000000001 1.277032377439511
1.00000000000000002 1.277032378456123
1.00000000000000003 1.277032380112478
I have another timeseries newTs with similar data, but many more rows. oldTs may have half a million rows, whereas newTs could have a million. I want to interpolate the data from the old timeseries with the new timeseries, for example:
interpolatedTs = interp(oldTs.time, oldTs.data, newTs.time)
This is giving me an error: x values must be distinct
The thing is, my x values are distinct. I think that MATLAB may be truncating some of the data, and therefore believing that some of the data is not unique. I found that other MATLAB functions do this:
test = [1.00000000000000001, 1.00000000000000002, 1.0000000000000000003]
unique(test)
ans =
1
test2 = [10000000000000000001, 10000000000000000002, 10000000000000000003]
unique(test2)
ans =
1.000000000000000e+19
MATLAB thinks that this vector only has one unique value in it instead of three! This is a huge issue for me, as I need to maintain the highest level of accuracy and precision with my data, and I cannot sacrifice any of that precision. Speed/Storage is not a factor.
Do certain MATLAB functions, by default, truncate data at a certain nth decimal? Has this changed from MATLAB 2012 to MATLAB 2016? Is there a way to force MATLAB to use a certain precision for a program? Why does MATLAB do this to begin with?
Any light shed on this topic is much appreciated. Thanks.
No, this has not changed since 2012, nor since the very first version of MATLAB. MATLAB uses, and has always used, double precision floating point values by default (8 bytes). The first value larger than 1 that can be represented is 1 + eps(1), with eps(1) = 2.2204e-16. Basically you have less than 16 decimal digits to play with. Your value 1.00000000000000001 is identical to 1 in double precision floating point representation.
Note that this is not something specific to MATLAB, it is a standard that your hardware conforms to. MATLAB simply uses your hardware's capabilities.
Use the variable precision arithmetic from the Symbolic Math Toolbox to work with higher precision numbers:
data = [vpa(1) + 0.00000000000000001
vpa(1) + 0.00000000000000002
vpa(1) + 0.00000000000000003]
data =
1.00000000000000001
1.00000000000000002
1.00000000000000003
Note that vpa(1.00000000000000001) will not work, as the number is first interpreted as a double-precision float value, and only after converted to VPA, but the damage has already been done at that point.
Note also that arithmetic with VPA is a lot slower, and some operations might not be possible at all.

How to multiply numbers in Swift?

I am working on a calculator in Swift, but I have a small problem:
when multiplying two numbers, I don't have the same results as a regular calculator.
For example:
In Swift :
0.333328247070312 * 16 = 5.33325195312499
In a regular calculator:
0.333328247070312 * 16 = 5.333251953
What should I do to get the same results as a regular calculator in Swift?
Your "regular calculator" seems wrong or weird in result printing, so, you should not rely on it. I've rechecked your calculation in Python3 which is known to calculate all in binary64 double and print the most exact decimal form:
>>> 0.333328247070312 * 16
5.333251953124992
it's even more detailed (by one digit) than Swift output. Your output also can't be verified as binary32 calculation, because the latter has ~7 correct decimal digits, and usually isn't printed with more digits. What this calculator is? I'd suppose some Pascal-based tool due to its custom 6-byte float.
Try to ask your calculator to print the most detailed form. If it fails, throw it away and use a most exact tool to verify, or, if your task is really to get the same result, figure out more details about its processing.

Random Number in Octave

I need to generate a random number that is between .0000001 and 1, I have been using rand(1) but this only gives me 4 decimal points, is there any other way to do this generation?
Thanks!
From the Octave docs:
By default, Octave displays 5 significant digits in a human readable form (option ‘short’ paired with ‘loose’ format for matrices).
So it's probably an issue with the way you're printing the value rather than the value itself.
That same page shows the other output formats in addition to short, the one you may want to look in to is long, giving 15 significant digits.
And there is also the output_precision which can be set as per here:
old_val = output_precision (7)
disp (whatever)
old_val = output_precision (old_val)
Set the output_precision to 7 and it should be ok :)
Setting the output precision won't help though because the number can still be less than .0000001 in theory but you will only be displaying the first 7 digits. The simplest way is:
req=0;
while (req<.0000001)
req=rand(1);
end
It is possible that this could get you stuck in a loop but it will produce the right number. To display all the decimals you can also use the following command:
format long
This will show you 15 decimal places. To switch back go:
formay short

Matlab number formatting?

I'm having some difficulties processing some numbers. The results I get are some like:
0.000093145+1.6437e-011i
0.00009235+4.5068e-009i
I've already try to use format long and as alternative passing to string and then str2num and with no good results also. Although is not being possible to convert them properly as I want (e.g. to a number with 9 decimals) If nobody is able to help me, at least I would appreciate if someone can tell me how to interpret the meaning of the i base.
You are talking about the imaginary unit i. If you are just using real number, you could neglect the imaginary part (it is very small). Thus, try:
real(0.000093145+1.6437e-011i)
After taking real() you can also control the decimal place formatting by sprintf:
sprintf('%0.2f', pi)
Will result in:
'3.14'
Place a 9 instead of a 2 for 9 decimal places.

Adding 1 to very small numbers

I have a question about adding the number 1 to very small numbers. Right now, I am trying to plot a circular arc in the complex plane centered around the real number 1. My code looks like:
arc = 1 + rho .* exp(1i.*theta);
The value rho is a very small number, and theta runs from 0 to pi, so whenever 1 is added to the real part of arc, MATLAB seems to just round it to 1, so when I type in plot(real(arc),imag(arc)), all I see is a spike instead of a semicircle around 1. Does anyone know how to remedy this so that MATLAB will not round 1 + real(arc) to 1, and instead conserve the precision?
Thanks
rho=1e-6; theta=0:pi/100:pi; arc=1+rho*exp(1i.*theta); plot(arc); figure(); plot(arc-1);
Shows, that the problem is in plot, not in loss of precision. After rho<1e-13 there will be expected trouble with precision.
The two other possible misconceptions:
- doubles have finite precision. 16 decimal digits or 1+2^-52 is the limit with doubles.
- format short vs. format long -- matlab shows by default only 6 or 7 digits
It also happens to be that 6-7 digits is the limit of a 32-bit float, which could explain also that perhaps the plot function in Octave 3.4.3 is also implemented with floats.
Left: 1+1e-6*exp, Right: (1+1e-6*exp)-1
There is a builtin solution for exactly this probem:
exp1m()
log1p()
explicitly:
log(arc)=log1p(rho*exp(1i*theta))
to get what you need.
Of course you need to work in log space to represent this precision, but this is the typical way this is done.
In double precision floating point representations, the smallest number strictly greater than 1 that can be represented is 1 + 2^-52.
This is a limitation imposed by the way non-integer numbers are represented on most machines that can be avoided in software, but not easily. See this question about approaches for MATLAB.