|  | unsigned long to double |  | |
| | | Richard Harnden |  |
| Posted: Thu Sep 04, 2008 11:02 am Post subject: unsigned long to double |  |
| |  | |
Hi,
I've got a list of longs which I need to fix.
Basically the numbers come from an unsigned long, which will wrap back to zero. I need them unwrapped.
Also, my data will come from a database which doesn't have an unsigned long datatype ... they appear as long.
Does the following actually do what I hope it does?
#include <stdio.h> #include <math.h> #include <limits.h>
int main(void) { long testme[] = { 1649354396, -1512698780, -365331864, 856092536, 2076605992, -1006418300, 191408540, 1462864659, -1502144861, -269042670, 910116600, 2098697218, -971310087, 325728931, 1622242763, -1378801075 }; size_t n = sizeof(testme) / sizeof(testme[0]); size_t i; unsigned long max = ULONG_MAX; int wrapped = 0; double value; double prior_value = 0.0;
for (i=0; i<n; i++) { value = testme[i] + (wrapped * (double) max);
if ( value < prior_value ) { wrapped++; value += (double) max; }
printf("%ld -> %g\n", testme[i], value);
prior_value = value; }
return 0; } |
| |
| | | Eric Sosman |  |
| Posted: Thu Sep 04, 2008 11:10 am Post subject: Re: unsigned long to double |  |
| |  | |
Richard Harnden wrote:
| Quote: | Hi,
I've got a list of longs which I need to fix.
Basically the numbers come from an unsigned long, which will wrap back to zero. I need them unwrapped.
Also, my data will come from a database which doesn't have an unsigned long datatype ... they appear as long.
Does the following actually do what I hope it does?
#include <stdio.h #include <math.h #include <limits.h
int main(void) { long testme[] = { 1649354396, -1512698780, -365331864, 856092536, 2076605992, -1006418300, 191408540, 1462864659, -1502144861, -269042670, 910116600, 2098697218, -971310087, 325728931, 1622242763, -1378801075 }; size_t n = sizeof(testme) / sizeof(testme[0]); size_t i; unsigned long max = ULONG_MAX; int wrapped = 0; double value; double prior_value = 0.0;
for (i=0; i<n; i++) { value = testme[i] + (wrapped * (double) max);
|
Off by one here: The modulus is not ULONG_MAX, but one greater. (The problem might even be gnarlier, depending on how the original data was transformed along its route to and from your database.)
| Quote: | if ( value < prior_value ) { wrapped++; value += (double) max;
|
Same error.
| Quote: | }
printf("%ld -> %g\n", testme[i], value);
prior_value = value; }
return 0; }
|
It looks like you started with a non-decreasing sequence of numbers, but only their low-order bits have been retained. So you look for places where the value steps downward instead of upward, and at each such place you say "Aha! this is where the lost high-order part increased." That's fine, but how do you know the lost bits increased by just one step, that there was only one wrap-around? Even between one number and a larger successor there could have been wrap-around. Unless you know something about the spacing of the samples vis-a-vis the rate of change of what they measure, lost is lost.
-- Eric Sosman esosman@ieee-dot-org.invalid |
| |
| | | Ben Bacarisse |  |
| Posted: Thu Sep 04, 2008 11:13 am Post subject: Re: unsigned long to double |  |
| |  | |
Richard Harnden <richard.harnden@googlemail.com> writes:
| Quote: | I've got a list of longs which I need to fix.
Basically the numbers come from an unsigned long, which will wrap back to zero. I need them unwrapped.
Also, my data will come from a database which doesn't have an unsigned long datatype ... they appear as long.
Does the following actually do what I hope it does?
|
Not quite (I think). It was only by reading the code I could decode what you intended and if the code was further off the mark I would have had to guess even more. I may still have guessed wrong!
Here is what I think you are doing: you have some process that produces a sequence of numbers that you know to be strictly increasing. However, due to some code you can't change, all you see is the result after the sequence has been converted to a fixed-size signed integer (long in this case) and from these numbers you need to re-create the original sequence.
You can't do this from the data you have unless you add in the assumption that the increments are never more than the maximum value of an unsigned long. Give that assumption, your code is almost correct but:
| Quote: | #include <stdio.h #include <math.h #include <limits.h
int main(void) { long testme[] = { 1649354396, -1512698780, -365331864, 856092536, 2076605992, -1006418300, 191408540, 1462864659, -1502144861, -269042670, 910116600, 2098697218, -971310087, 325728931, 1622242763, -1378801075 }; size_t n = sizeof(testme) / sizeof(testme[0]); size_t i; unsigned long max = ULONG_MAX; int wrapped = 0; double value; double prior_value = 0.0;
for (i=0; i<n; i++) { value = testme[i] + (wrapped * (double) max);
|
The value to multiply by should be max + 1. Clearly you need to write that as + (wrapped * ((double)max + 1)) or some such.
| Quote: | if ( value < prior_value ) { wrapped++; value += (double) max;
|
and again you need (double)max + 1 here. I'd define a double holding (double)ULONG_MAX + 1 and use that instead of max.
| Quote: | }
printf("%ld -> %g\n", testme[i], value);
prior_value = value; }
return 0; }
|
There may also be problems using floating point arithmetic, especially if the sequence is a long one. Can you use unsigned long long instead?
-- Ben. |
| |
| | | viza |  |
| Posted: Thu Sep 04, 2008 11:44 am Post subject: Re: unsigned long to double |  |
| |  | |
On Thu, 04 Sep 2008 04:02:18 -0700, Richard Harnden wrote:
| Quote: | I've got a list of longs which I need to fix.
Basically the numbers come from an unsigned long, which will wrap back to zero. I need them unwrapped.
Also, my data will come from a database which doesn't have an unsigned long datatype ... they appear as long.
Does the following actually do what I hope it does?
|
Doing this in floating point is a very bad idea. On most systems double cannot represent all the integers in the range of long, so if you have large numbers they will get rounded to the nearest multiple of two or four or eight etc, depending on their mangitude.
It is also much slower.
Converting an unsigned long int to a long int produces implementation defined results if is outside the range of long int, so you need to test what the output of the system that put the numbers into the database, but in most cases, it is sufficient to do:
{ long testme= FOO; unsigned long corrected;
corrected= testme; }
HTH viza |
| |
| | | Boon |  |
| Posted: Thu Sep 04, 2008 1:30 pm Post subject: Re: unsigned long to double |  |
viza wrote:
| Quote: | Doing this in floating point is a very bad idea. On most systems double cannot represent all the integers in the range of long,
|
Are you thinking of systems where longs are 64-bits wide? |
| |
| | | viza |  |
| Posted: Thu Sep 04, 2008 2:46 pm Post subject: Re: unsigned long to double |  |
On Thu, 04 Sep 2008 08:33:42 -0700, jameskuyper wrote:
| Quote: | viza wrote: On most systems double cannot represent all the integers in the range of long
I agree that you should not write code which assumes that long integers can be converted to double without loss of precision. However, I'm think that you may be overstating your case by using the word "most".
|
perhaps ..."most systems (that I'm sitting at)"...
 |
| |
| | | Guest |  |
| Posted: Thu Sep 04, 2008 3:33 pm Post subject: Re: unsigned long to double |  |
viza wrote:
| Quote: | ... On most systems double cannot represent all the integers in the range of long, so if you have
|
I agree that you should not write code which assumes that long integers can be converted to double without loss of precision. However, I'm think that you may be overstating your case by using the word "most". I don't know exact numbers, but it seems to me that implementations with 32-bit longs are still pretty common. The standard permits "double" to have insufficient precision to represent a 32-bit integer, but I doubt that implementations where this is the case are common. Most implementations I'm familiar with use IEEE format double precision, which has nearly twice that capacity. |
| |
| | | Richard Harnden |  |
| Posted: Thu Sep 04, 2008 4:46 pm Post subject: Re: unsigned long to double |  |
| |  | |
On 4 Sep, 14:10, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
| Quote: | Richard Harnden wrote: unsigned long max = ULONG_MAX; int wrapped = 0; [...] for (i=0; i<n; i++) { value = testme[i] + (wrapped * (double) max);
Off by one here: The modulus is not ULONG_MAX, but one greater. (The problem might even be gnarlier, depending on how the original data was transformed along its route to and from your database.)
|
Right, thanks. I'll do what Ben said and use a 'double max (double)ULONG_MAX + 1;'
| Quote: | It looks like you started with a non-decreasing sequence of numbers, but only their low-order bits have been retained. So you look for places where the value steps downward instead of upward, and at each such place you say "Aha! this is where the lost high-order part increased." That's fine, but how do you know the lost bits increased by just one step, that there was only one wrap-around? Even between one number and a larger successor there could have been wrap-around. Unless you know something about the spacing of the samples vis-a-vis the rate of change of what they measure, lost is lost.
|
That's it exactly. A sample is taken every hour, but it could easily wrap-around more than once during that interval. I guess that I'll have to sample more frequently, especially since it's any sudden spurts of activity that I'm interested in.
Thanks for your help. |
| |
|
|