Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

hpgcc3 denormalized reals

78 views
Skip to first unread message

Wes

unread,
Dec 28, 2011, 4:01:52 AM12/28/11
to
I noticed that in hpgcc3 when pushing doubles onto the stack as reals,
some values produce denormalized values. You won't notice the problem
when the calculator's Number Format is set to STD, but you'll see it
using FIX, SCI, or ENG.

For example,

sat3_push_dbl_real(8.1); // corrected pushes 8.1 (8.1e0) onto the
stack
sat3_push_dbl_real(9.1); // incorrected pushes 09.1 (0.91e1) onto
the stack

sat3_push_dbl_real(810.0); // corrected pushes 810.0 (8.1e2) onto
the stack
sat3_push_dbl_real(910.0); // incorrected pushes 0,910.0 (0.91e3)
onto the stack

The non-normalized values are produced when the significand is in the
interval 9.00719925475 <= x < 10.0. The value of the pushed number is
correct, just not normalized.

I've tried tracking down the problem, but not having a debugger slows
down the process. Perhaps someone more familiar with the
__sat3_dbl2real() function can shed some light on the matter.

(I seem to recall that hpgcc2 also originally had problems converting
certain values from ieee double to hp real, as did HPStack/HPParse.)

denormalized, but not demoralized,
-wes

Wes

unread,
Dec 28, 2011, 3:06:40 PM12/28/11
to
> but not having a debugger slows down the process.

In trying to debug, I also noticed that outputting doubles with printf
is not working.

double f = 1.234;
printf("%f\n",f);

prints out a long list of incorrect digits. Can anyone else confirm
this?

(I also tried it with the unnecessary l flag "%lf" with no change.)

I am using hpgcc3 R0002. My memory could be faulty, but I thought
"%f" worked with R0001.

-wes

Wes

unread,
Dec 29, 2011, 9:41:27 AM12/29/11
to
On Dec 28, 12:01 pm, Wes <wjltemp...@yahoo.com> wrote:
> I noticed that in hpgcc3 when pushing doubles onto the stack as reals,
> some values produce denormalized values. You won't notice the problem
> when the calculator's Number Format is set to STD, but you'll see it
> using FIX, SCI, or ENG.

I've been playing around with the library code and rewrote
__sat3_dbl2real() from scratch (see below). I did a clean rebuild of
everything and all seems to be working correctly. It could probably
be tweaked a little, but it gets the job done and I think the logic is
reasonably easy to follow.

----------------------------------------------------
// Wes Loewer
// 12/29/2011

// log10(2)
#define LOG10OF2 0.30102999566398119521373889

typedef union {
ULONGLONG real; // HP REAL, without prologue
struct {
unsigned exp10 :12; // 3 nibbles
unsigned long long mant10 :48; // 12 nibbles
unsigned sign : 4; // 4 nibbles
};
} hpreal_t;


ULONGLONG __sat3_dbl2real(double x)
{
int carry;
int exp2p1, exp10, i, istop;
double pow10, tenpow10, digit;
hpreal_t r;
unsigned char mant[13]; // one extra digit to allow for rounding
9.999... up to 10.0

r.exp10 = 0; // initialize exponent
r.mant10 = 0; // initialize mantissa
r.sign = x<0 ? 9 : 0; // 9 for negative, 0 for positive or zero

// if (x == 0) then just use the initialized values
if (x != 0.0)
{
x = fabs(x); // use |x| from here on out
frexp(x,&exp2p1); // extract smallest power of 2 > to
x, x!=0
// exp2p1-1 is largest power of 2 <= to x
exp10 = (int)floor((exp2p1-1)*LOG10OF2); // approximate exp10,
could be off by one
pow10 = i10powx(exp10); // largest power of 10 <= to x


// correct any error in exp10 approximation
tenpow10 = 10.0*pow10;
if (tenpow10 <= x)
{
pow10 = tenpow10;
exp10++;
}
else if (pow10 > x) // just to be sure, but I don't think this
is actually possible
{
pow10 /= 10.0;
exp10--;
}

x /= pow10; // x is now the positive significand of the
original x, in the inteval [1,10)

// set exponent in bcd
if (exp10 < 0) // negatives exponents are stored as
1000+exp
exp10 += 1000;
r.exp10 = exp10 % 10; // least significant digit
exp10 /= 10;
r.exp10 |= (exp10 % 10)<<4; // middle digit
exp10 /= 10;
r.exp10 |= (exp10 % 10)<<8; // most significant digit

// set mantissa in bcd, starting with msd in mant[1]
mant[0]=0; // leave mant[0] for possible rounding later
for (i=1; i<13; i++)
{
modf(x,&digit);
mant[i] = (unsigned)digit;
x = (x-digit)*10.0;
}
// check to see if values need rounding
// (this also takes care of repeating 9's)
if (x>=5)
{
carry = 1; // true
i=12;
do
{
mant[i]++; // add the carried 1
if (mant[i] == 10) // is the new digit 10?
mant[i] = 0; // then make it 0 and carry the 1
else
carry = 0; // false, has to eventually get here since
mant[0] is either 0 or 1
i--;
}
while (carry);
}
// start i so as to skip a leading zero
if (mant[0]==0)
{
i = 1;
istop = 12;
}
else
{
i = 0;
istop = 11;
}

// now copy the 12 rounded mantissa digits to r.mant10, starting
with msd
for (; i<=istop; i++)
r.mant10 = (r.mant10 << 4) | mant[i]; // shift 1 nibble and add
next digit
}

return r.real;
}
----------------------------------------------------

-wes

Claudio Lapilli

unread,
Jan 5, 2012, 7:48:08 AM1/5/12
to
Wes,
I will look into this issue as soon as I can.

Regards,
Claudio Lapilli

Wes

unread,
Jan 7, 2012, 5:35:27 AM1/7/12
to
On Jan 5, 3:48 pm, Claudio Lapilli <pleasedonts...@isp.com> wrote:
> Wes,
> I will look into this issue as soon as I can.
>
> Regards,
> Claudio Lapilli


I found an easily fixed problem in the __sat3_dbl2real() function I
posted. (I forgot to increment the exponent when 9.999... got rounded
up to 10.0) The correction is shown below.

FYI to anybody with hpgcc3: If you're using a virtual machine, take a
snapshot before you upgrade anything on your guest machine.

I made the mistake of upgrading my Ubuntu 11.04 to 11.10 which ugraded
Eclipse from 3.5.2 to 3.7, after which I upgraded the CodeSourcery
toolchain from 2011.03-42 to 2011.09-69. I don't know if it was from
the newer Ubuntu or Eclipse, but I found that building the HPGCC3_R002
tools and running the install_plugin.sh script did not create a HPGCC3
(Linux) toolchain option in Eclipse.

I ended up reinstalling the older Ubuntu and Eclipse and
install_plugin.sh installed correctly. However, I couldn't get the
libs to successfully compile a ROM until I also downgraded the
CodeSourcery toolchain back to 2011.03-42.

All was right with the hpgcc3 world again. (Besides, I _really_
disliked the new Ubuntu desktop anyway.)

-wes

// __sat3_dbl2real rewritten by Wes Loewer

// log10(2)
#define LOG10OF2
0.3010299956639811952137388947244930267681898814621085413104
// set mantissa in bcd, starting with msd in mant[1]
mant[0]=0; // leave mant[0] for possible rounding later
for (i=1; i<13; i++)
{
modf(x,&digit);
mant[i] = (unsigned)digit;
x = (x-digit)*10.0;
}
// check to see if values need rounding
// (this also takes care of repeating 9's)
if (x>=5)
{
carry = 1; // true
i = 12;
do
{
mant[i]++; // add the carried 1
if (mant[i] == 10) // is the new digit 10?
mant[i] = 0; // then make it 0 and carry the 1
else
carry = 0; // false, has to eventually get here since
mant[0] is either 0 or 1
i--;
}
while (carry);
}
// start i so as to skip a leading zero
if (mant[0]==0) // if msd was not a 9 rounded up to 10
{
i = 1;
istop = 12;
}
else // else msd was a 9 rounded up to 10
{
i = 0;
istop = 11;
exp10++; // 9.999...e(N) becomes 1.0e(N+1)
}

// now copy 12 rounded mantissa digits to r.mant10, starting with
msd
for (; i<=istop; i++)
r.mant10 = (r.mant10 << 4) | mant[i]; // shift 1 nibble and add
next digit

// finally, set exponent in bcd
if (exp10 < 0) // negatives exponents are stored as
1000+exp
exp10 += 1000;
r.exp10 = exp10 % 10; // least significant digit
exp10 /= 10;
r.exp10 |= (exp10 % 10)<<4; // middle digit
exp10 /= 10;
r.exp10 |= (exp10 % 10)<<8; // most significant digit

}

return r.real;
}
0 new messages