Here's the part where I probably went wrong. I assumed that the calculation registers are big enough for 'everything' and the var to be stored in limits you to good or overflowed storage. The _Integer64 would be fine.
@SMcNeill 's explanation of 80bit FP for x86 and 64bit for x64 calculations confirms this idea. But the dark magic under the hood thinks different ;-)
So is the compiiler breaking up calculatings, and does it execute calcultations with Single var's in a smaller register? Hence the rounding as @luke illustrates? Just trying to understand, to be able to prevent these nasty coding errors.
I should emphasise that the results you're seeing with QB64-64 are the "correct" results, in that it's the expected value - so that won't be changing in the future unless someone can convince me otherwise. The intermediate mode of the FPU that Steve mentioned doesn't really come into play, since I'm running the calculations on a fixed development copy (technically a Linux version which never had the bug, but the point stands).
PRINT's decision to use scientific notation isn't really reflective of anything other than a formatting rule, so you can't read into it too much either way.
The rule for the arithmetic operations (+-*/) is basically that the value of lesser type is converted to the greater type, and the result is a value of the greater type. Here "lesser" and "greater" refer to an ordering of the types, which basically runs, from least to greatest: _byte, integer, long, _integer64, single, double, _float. One exception is that the / (division) operator always converts its arguments and returns a floating-point number, for obvious reasons. So in this small program:
The result of the subtraction is of Single type.
It also turns out that because of the nature of floating point numbers, there are some numbers that can't be represented. For a Single, you have 24 bits (technically 23 + 1 implicit bit) that work as a regular value, so you can store every integer up to 16777216 (2^24). But beyond that you can only store some integers:
(Notice because b is a Single, the addition operation gives a Single result.) The number 16777217 simply can't be represented, so the result is rounded to a representable number. In this particular case we could fix the issue by making 1 a Double, which causes b to get converted to a Double and the result to be a Double:
Now, it turns out that 31536000 can be stored in a Single... but the result of (tm_year - 70) * 31536000 can't. We can see this using the Print Using trick again:
tm_year = 1978
a = (tm_year - 70) * 31536000
Note that if you just do a straight-up "1908 * 31536000" you'll get a nonsense answer because the constants are of type Long and the result is bigger than will fit in a Long; using a Single or _Integer64 variable causes the type of the intermediate expressions to be greater.
It's coming into midnight (or 1am if you count the impending daylight saving change) and I'm not quite sure what the message of the post is anymore. Anyway, if you want to do maths with big numbers and can't accept some rounding, best to make everything an _Integer64 and it should all work out.