[Swan-dev] tricky arithmetic

D. Hugh Redelmeier hugh at mimosa.com
Sun Feb 1 05:13:18 EET 2015


| From: Antony Antony <antony at phenome.org>

| On Fri, Jan 30, 2015 at 04:54:06PM -0500, D. Hugh Redelmeier wrote:
| > | From: Antony Antony <antony at phenome.org>
| > | 
| > | On Wed, Jan 28, 2015 at 06:21:58PM -0500, D. Hugh Redelmeier wrote:

| the spec said __suseconds_t could be -1. If that happens unsigned long will print big number? 

Nit: the spec says nothing about __suseconds_t.  It talks about
suseconds_t.

The type suseconds must be able to represent -1.  The specification of
gettimeofday does not seem to allow for this result.  The same story
for 1000000.

BTW, the Single Unix Standard seems to suggest that gettimeofday is
obsolete and that clock_getime should be used instead.  It uses struct
timespec (with nanosecond precision) instead of struct timeval (with
microsecond precision).  I guess we should do that.  Does libevent
understand struct timespec or must we use struct timeval for it?

| > I think that it worked, without diagnostic, before you changed it.  (I
| > admit: I didn't test it.)
| > 
| > You have no reasonable way of knowing what the underlaying type of
| > suseconds_t is.  It is not always int since int might not be able to
| > represent 1000000.  Changing it to int is a bug.
| 
| 
| > On some C implementations, the type "int" is too small too represent
| > 1000000.  So you know that suseconds_t might not be int.
| 
| I don't undersant why "long int" %ld would not be sufficient and we need "unsigned long".

You wrote int, not long int.

long int is sufficient and so is unsigned long.  Which is simpler?
Since we are trying to deal with a non-negative number, unsigned long
seems simpler.  If the result were negative, think of the odd
printout!

| > suseconds_t may or may not be long, but long is large enough to
| > represent all values.
| > 
| > In this case, unsigned long can also represent all values.  And it is
| > simpler to understand because a negative value would not be
| > reasonable and must not occur.
| 
| So the judgment to use unsigned is based on -1 is unresasonable and not 
| what standard state, standard state -1 is possibilty?

I can find no place where that says gettimeofday can return a result with 
the tv_usec member less than 0 (or as large as 1000000).

I can imagine the utility of allowing gettimeofday's tv_usec to be any 
negative number down to -1000000, but that isn't legal.  I cannot imagine 
the utility of allowing only -1.

My supposition is that

1) the standard wanted to force the type to be signed because it had been 
   so historically (search for suseconds_t in 
   <http://www.unix.org/version2/whatsnew/datasize.html>)

2) the standard wanted the negative numbers to be forbidden (otherwise the 
   limit would be -1000000).

| > For similar reasons, changing the type of "borrow" to int is wrong
| > too:
| > 	borrow * 1000000  <==== can overflow
| > 
| > |  warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘__suseconds_t’ [-Wformat=] 
| > 
| > It is being very kind to you: reporting a portability error.
| > 
| > I suggest reverting 87590de5401c0e0bd4eaf93bb02c68eca544990a
| 
| only base to revert this commit is your judgement. My prefernce is long int. I happy to revert.

Where long unsigned fails, long int will fail too.

| > I don't really care for using floating point when it isn't necessary
| > or natural.  But natural is in the eye of the beholder.
| 
| Since we are entering subsecond relam there will be lot of subsecond 
| computations and formatted out. Some clarity and best practice on how to 
| store and output this would be nice.

It is easy to do this kind of arithmetic.  Just what they taught us in 
grade school.  We're working with two-digit numbers, but the base is 
really large.

The short bit of code we're talking about shows how to subtract two
struc timeval values and how to print one.  This code assumed that the
result would be positive (negative would have been nonsense).

When things get slightly tricky, we invent abstractions.  That's one
reason that I've repeatedly urged you to use a distinct type for these
values.

Floating point arithetic is a powerful abstraction.  It is way more
powerful than we need or want and it has some surprising properties.
In fact, there is a strong hint from the system that time is well
represented in struct timeval or perhaps struct timespec.


More information about the Swan-dev mailing list