Keith Thompson said:
John F said:
There is a difference between
(date1+date2)/2 (adds dates and divides by two)
and
date1+(date2-date1)/2 (proportionally adds the difference between
two
dates to another date)
The former is meaningless (in a mathematical sense), the latter is
perfectly legal.
[...]
The former includes a subexpression that yields a result that's not
meaningful, but the expression has a whole is meaningful.
Thanks for clarification. I was referring to the math behind it where
it yealds an error in the domain ot the binary operator +...
Dates, temperatures, and pointers are all similar in the sense that
each can be thought of as a pair: base+offset, where the base is
respectively an arbitrary epoch, an arbitrary zero temperature, or a
zero address (or the base address of a containing object). In each
case, the "base" is some fixed point, and the "offset" is a scalar
quantity. Offsets by themselves can be added and subtracted freely;
the base is meaningful only if you have exactly zero or one of it.
(With no base, you have an interval or distance; with a base, you
have
a position.)
(Assume Celsius or Fahrenheit temperatures; the zero base of Kelvin
scale is uniquely meaningful, so it's not restricted to this model.)
Subtracting two dates
date1 - date2
is equivalent to:
(base+offset1) - (base+offset2)
which reduces to:
offset1 - offset2
which is meaningful; it's an interval, measurable in seconds, with
no
defined base.
Exactly. At least if you assume the same base for the representation,
and the same scale for the offset too.
Adding two dates:
date1 + date2
is equivalent to:
(base+offset1) + (base+offset2)
which reduces to:
2*base + offset1 - offset2
which is not directly meaningful because of the 2*base term.
Exactly. You can't tell what it should be. Same applies as above. Same
scale for the offset and a common base can be found to set the base_x
values. Which should be quite hard for a time-scale. One can always go
back and back... With temperature a natural limit showed up with
absolute zero.
Have you ever tried to translate a chinese date into the gregorian
calendar? It is really nice.
However, if it's used as an intermediate expression, as in:
(date1 + date2) / 2
we have
((base+offset1) + (base+offset2)) / 2
or
(2*base + offset1 - offset2) / 2
or
base + (offset1 - offset2)/2
a meaningful expression that denotes the midpoint between the two
dates.
Again assuming a common base and the same scale for the offset. (just
to remind
Ideally, we'd like to make expressions with meaningful results
legal,
and expressions without meaningful results illegal. Theoretically,
we
could do this by allowing meaningless intermediate results, as long
as
the result of the full expression is meaningful.
Agreed.
There are (at least) two problems with this approach. First, it
makes
the language rules more complex, which affects both compiler writers
(who can deal with it) and users (who likely can't). Try explaining
to a newbie that (date1 + date2), or (pointer1 + pointer2), is
usually
illegal, except that it's allowed as a subexpression if and only if
the expression as a whole obeys certain constraints.
I don't want to do that. Really. Avoiding objects where intermediate
results can't be illegal as a whole would fix 80% of all bugs, I
guess.
Second, it makes
it difficult to define the circumstances in which overflow can
occur.
Yes.
Pointer arithmetic in C is defined only within a single object (or
just past its end); allowing pointer+pointer gives you intermediate
results that not only don't have an obvious meaning, but may not be
representable, depending on where in the address space the object
happens to be allocated.
Exactly. It would be hard to implement too.
Ignoring the overflow problem, if you're using raw numbers to
represent dates, something like (date1+date2)/2 is ok, as long as
you
have the discipline to avoid writing a full expression that's not
meaningful:
x = date1 + date2; /* meaningless, but the compiler won't
complain */
At least with weak checking. One could argue that we could define a
type
"SOD" (Sum of dates" and you would need to make this type illegal for
an lvalue.
the "2" in the expression
x=(date1 + date2)/2 should get type "DD" (DateDevider)
and [SOD]/[DD] = [D] such that x would get type D again. It is a lot
of brainy stuff, but should work. (never seen a language with such a
feature (except VB with its "Variant", where almost every operation
yealds a meaningful result (regarding the type)))
I'd rather have a function x = mediandate( date1, date2 ); for that
job.
If you're using a hypothetical language that does this kind of smart
type checking, allowing date1+date2 as a subexpression but not as a
full expression, you can add dates to your heart's content and
depend
on the implementation to detect any type matching errors. It would
be
interesting to design this kind of thing, either as a language
feature
(off-topic here), or as a library with run-time checking (doable in
standard C, with functions rather than overloaded operators).
Again,
overflow is a concern unless you can either use extended precision
for
intermediate results, or rely on the implementation to rearrange the
expressions for you.
Using the natural division: char for day, char for month, long long
for year and double for the seconds within a day it shouldn't be any
problem. It is all a matter of promotion
Finally, if you're using standard C and operating on pointers,
you'll
just have to rearrange the expression yourself. If you need to know
the address halfway between two pointers, you can't write:
mid = (ptr1 + ptr2) / 2;
You'll just have to bite the bullet and write:
mid = ptr1 + (ptr2 - ptr1) / 2;
One should add: for ptr2 >= ptr1.
(never seen a negative pointer in C)
(sorry for the long post, thanks for reading up till here)