2

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?

  • 2
    why don't just use `km = now * 299.792458;` instead of `km = (now / 1000.0) * 299792.458;`? – phuclv Jan 31 '16 at 05:49
  • @LưuVĩnhPhúc Used your suggestion in [my answer](http://stackoverflow.com/a/35111025/5221149). Helped simplify the code. Thanks. – Andreas Jan 31 '16 at 06:32

2 Answers2

4

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
Community
  • 1
  • 1
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • 1
    This gives more decimal digits, but since the speed of light was only given with 9 significant digits only about the first 9 digits of the result are relevant. – Henry Jan 31 '16 at 07:26
  • 2
    @Henry The 9 digits is the exact [speed of light](https://en.wikipedia.org/wiki/Speed_of_light): *"Its **precise value is 299792458 metres per second** (approximately 3.00×10⁸ m/s), since the length of the metre is defined from this constant and the international standard for time."* No rounding, so calculating with more than 16 digits of precision is valid. – Andreas Jan 31 '16 at 07:38
  • Yes you are right, it works in this case. Still I will leave my comment in as a warning that for other physical constants it may not make sense to give lots of digits in the result. – Henry Jan 31 '16 at 07:49
  • 1
    Digging a bit deeper, there is actually a problem with the accuracy of the time value since UNIX time stamps do not take into account leap seconds. See for example http://stackoverflow.com/questions/16539436/unix-time-and-leap-seconds. This is a systematic error and could be corrected though. – Henry Jan 31 '16 at 08:19
  • Thank you. Is there another way of doing this without using BigDecimal? It works fine, but I'm sure there's a way to do it without BigDecimal. – clownfishhuman Feb 01 '16 at 17:15
  • @GalenAsphaug *"I'm sure"*? Based on what? `BigDecimal` is intended for something like this, and there is no primitive type that can handle the precision, so I don't believe there is any other choice, unless you use a third-party library, and what would be the purpose of that? `BigDecimal` is built-in, and does the job perfectly. – Andreas Feb 01 '16 at 17:41
0

Just format it to three places, try this.

System.out.printf("Since the unix Epoch, light has traveled...\n%.3f km", km);
DominicEU
  • 3,585
  • 2
  • 21
  • 32