Will these statements execute with exactly the same results across different platforms?
currentTime = System . nanoTime ( ) * 0.000000001f ; // 01
currentTime = System . nanoTime ( ) / 1000000000f ; // 02
The concern is loss of precision using a small floating point value.
Just leave it as a long. No loss of precision and perfect Determinism across the board.
Related
Working on a Java class, its making me crazy because this expression is evaluating to zero, I need it to evaluate to a double, then round it down to the nearest int. So what Im trying to get is for days to be a whole number of days, yet when I run it through java it evaluates to 0. When I run it through my calculator it evaluates to the correct value. I would love a fix and an explanation to why this what I already have isn't working.
public int getEventDays(){
//variables
double daysCalc;
int days;
//logic
if (getStatus().equals("filling")){
//this is indented less to fit everything on one line, its not this way in
//the fractions are for unit conversion
daysCalc= Math.floor(((capacity-storage)/(inflow-outflow))*(43560)*(1/3600)*(1/24));
days = (int)daysCalc;
}
else if (getStatus().equals("emptying")){
//this is indented less to fit everything
//the fractions are for unit conversion
daysCalc=Math.floor(((storage-0)/(outflow-inflow))*(43560)*(1/3600)*(1/24));
days = (int)daysCalc;
}
else{
days = -1;
}
return days;
}
Change your code to this :
daysCalc = Math.floor(((storage-0)/(outflow-inflow))*(43560)*(1.0/3600)*(1.0/24));
Explanation:
The right hand expression is returning an integer value. In your case, 1/3600 is rounded to 0, similar to the case of 1/24.
Now by using 1.0 instead of 1, it is giving the unrounded float value of 1/3600.
Your problem is connected with the order of operations within your expression. The parentheses around 1/3600 and 1/24 cause these expressions to be evaluated first - and since each of these divisions has an expression of integer type on either side of the division, it's treated as an integer division. In other words, 1/3600 and 1/24 are both evaluated as integers, to give a result of zero. This means that your arithmetic includes a couple of multiplications by zero, which is why your result is zero.
The simplest fix is to understand that multiplying by the reciprocal of some number is the same as dividing by that number. In other words, you could simplify the calculation to
daysCalc = Math.floor( storage / ( outflow - inflow ) * 43560 / 3600 / 24 );
which will give the correct result, provided storage, outflow and inflow are not all integers.
On the other hand, if storage, outflow and inflow are all integers, then you'll need to make sure that the first division is also not treated as an integer division. You could do this by writing
daysCalc = Math.floor((double) storage / ( outflow - inflow ) * 43560 / 3600 / 24 );
which forces the division to be done with floating point arithmetic; and thereafter, each one of the divisions is done in floating point.
I'm attempting to take the current system time,
long now = System.currentTimeMillis();
find out how far light has traveled since 1970 (in km),
double km = (now / 1000.0) * 299792.458;
and print the value.
System.out.printf("Since the unix Epoch, light has traveled...\n%f km", km);
But when I run the code, I'm only getting the answer down to two decimals.
435963358497001.750000 km
Is there a reason for this? Printing the value using
System.out.println(km);
gives me
4.3596335849700175E14
Seeing the E there makes sense why it cuts off. Is there a way I could get the value to 3 or more decimal places?
You are exceeding the precision of a double (15 to 17 decimal digits), so the result is rounded.
Try using BigDecimal instead:
long now = 1454217232166L; // Sun Jan 31 00:13:52 EST 2016
BigDecimal km = BigDecimal.valueOf(now).multiply(BigDecimal.valueOf(299.792458));
System.out.println(km); // prints: 435963358497001.804028
Just format it to three places, try this.
System.out.printf("Since the unix Epoch, light has traveled...\n%.3f km", km);
Using TimeUnit, how can I convert 665477 nanosecond to 0.665477 millisecond?
long t = TimeUnit.MILLISECONDS.convert(665477L, TimeUnit.NANOSECONDS);
This always gives 0 but I need decimal points precision.
From Java Documentation - TimeUnit#convert
public long convert(long sourceDuration,TimeUnit sourceUnit)
Convert the given time duration in the given unit to this unit.
Conversions from finer to coarser granularities truncate, so lose
precision. For example converting 999 milliseconds to seconds results
in 0. Conversions from coarser to finer granularities with arguments
that would numerically overflow saturate to Long.MIN_VALUE if negative
or Long.MAX_VALUE if positive.
So to get your answer
double milliseconds = 665477 / 1000000.0;
shorter and less error prone:
double millis = 665477 / 1E6;
milli -> mikro -> nano
are two steps, each step has a conversion faktor of 1000 = 1E3;
So makes one million, which can easier be read as 1E6, than by counting zeros.
Just divide by 1,000,000:
double millis = 665477 / 1000000.0;
With TimeUnit you will only get an integer result.
You can calculate this manualy
double mil = 665477L/1_000_000.0
double milliSeconds = nanoSeconds / (double) TimeUnit.MILLISECONDS.toNanos(1);
so you don't have to put the magic number 1_000_000.0 in your code, or remember what is the correct ratio to make sure there is no bug: the line is pretty self-validating.
You can import static java.util.concurrent.TimeUnit.MILLISECONDS; for a code reading even more like prose.
I am using Ruby to generate a 64 bit timestamp similar to Java. I went through Class:Time and it says time could use 63 bit integer. I thought I could use:
Time.now.to_f * 1000
but I am worried about losing precision due to the floating point conversion. Can I simply get the 64 bit timestamp (millis since epoch) as in Java in ruby, as precise as possible?
Calendar.getInstance().getTimeInMillis();
I need to use the timestamp as unique ID in a database, so I would like to keep time-related collisions from minimum to non-existent.
I've added comments suggesting this really isn't what you should be doing anyway, but I really don't think you need to worry about losing precision in any meaningful way. The Ruby documentation states that the value is stored down to the nanosecond. Converting it to a floating point number may lose the last few digits, but it's not going to be significant at the millisecond level - you really don't care if the value round up or down a bit, after all... you're already relying on only creating a single entry per millisecond.
An alternative approach would be to use to_i and nsec: multiply the result of to_i by 1000, divide the result of nsec by 1000000, and add the two together. That will get you the number of milliseconds using only integer arithmetic.
The time is signed long in Java so it is 63-bit also.
So you are worried that in this year you will get an overflow? Personally, I don't think anyone will be using Java by then. In fact it's likely we will be extinct/evolved by then as well.
System.out.println("Overflow at " + new Date(Long.MAX_VALUE));
prints
Overflow at Sun Aug 17 08:12:55 CET 292278994
Note: 292 million years ago was before the dinosaurs ruled the earth.
If you are concerned about the loss of accuracy of converting a nano-second time stamp to double you can calculate what that error is
long now = System.currentTimeMillis() * 1000000L;
double error_f = Math.ulp((float) now);
double error = Math.ulp((double) now);
System.out.println("The error for a nano-second timestamp using a double "
+ now + " is " + error + " and float is " + error_f);
prints
The error for a nano-second timestamp using a double 1378970569656000000 is 256.0 and float is 1.37438953472E11
This means the error for converting to double is up to half of this which is 128 ns, for converting to float, the error is also half the ulp, which is 68 seconds, which is quite high.
I need to store an exact audio position in a database, namely SQLite. I could store the frame position (sample offset / channels) as an integer, but this would cause extra data maintenance in case of certain file conversions.
So I'm thinking about storing the position as an 8 byte real value in seconds, that is a double, and so as a REAL in SQLite. That makes the database structure more consistent.
But, given a maximum samplerate of 192kHz, is the double precision sufficient so that I can always recover the exact frame position when multiplying the value by the samplerate?
Is there a certain maximum position above which an error may occur? What is this maximum position?
PS: this is about SQLite REAL, but also about the C and Java double type which may hold the position value at various stages.
Update:
Since the discussions now focus on the risks related to conversion and rounding, here's the C method that I'm planning to use:
// Given these types:
int samplerate;
long long framepos;
double position;
// First compute the position in seconds from the framepos:
position = (double) framepos / samplerate;
// Now store the position in an SQLite REAL column, and retrieve it later
// Then compute the framepos back from position, with rounding:
framepos = position * samplerate + 0.5;
Is this safe and symmetrical?
A double has 51 bits worth of precision. Depending on the exponent part, some of these bits will represent whole numbers (seconds in your case), the others fractions of seconds.
At 48 kilobits, a minimum of 16 bits is required to get the sub-second precise enough (more if rounding is not optimal). That leaves 35 bits for the seconds, which will span just over a thousand years.
So even if you need an extra bit or two for the sub-second to guard against rounding, and even if SQL loses a bit or two of precision converting it to decimal and back here and there, you aren't anywhere near losing sample precision with your double precision number. Make sure your rounding works correctly - C tends to always round down on convert to integer, so even an infintessimaly small conversion error could throw you off by 1.
I would store it as a (64-bit) integer representing microseconds (approx 2**20). This avoids floating point hardware/software, is readily understood by all, and gives you a range of 0..2**44 seconds which is a little over 55 thousand years.
As an alternative, use a readable fixed precision decimal representation (20 digits should be enough). Right-justified with leading zeros. The cost of conversion is negligible compared to DB accesses anyway.
One advantage of these options is that any database will trivially know how to order them, not necessarily obvious for floating point values.
As the answer by Matthias Wandel explains, there's probably nothing to worry about. OTOH by using integers you would get fixed precision regardless of the magnitude which might be useful.
Say, use a 64-bit integer, and store the time as microseconds. That gives you an equivalent sampling precision of 1 MHz and a range of almost 300000 years (if my quick calculation is correct).
Edit Even when taking into account the need for the timestamp * sample_rate to fit into a 64-bit integer, you still have a range of 1.5 years (2**63/1e6/3600/24/365/192e3), assuming a max sample rate of 192kHz.