* Copyright (c) 1982 Regents of the University of California
static char sccsid
[] = "@(#)bignum2.c 4.3 %G%";
Bignum Znumber
; /* zero reference */
#define MINEXP -32768 /* never generate; reserved for id 0 */
Bignum
intconvert(number
, convto
)
if (number
.num_tag
== convto
)
if (ty_nbyte
[number
.num_tag
] > ty_nbyte
[convto
] && (passno
== 2)){
yywarning("Conversion between %s and %s looses significance",
ty_string
[number
.num_tag
],
for (i
= ty_nbyte
[convto
]; i
< ty_nbyte
[TYPO
]; i
++)
#define CONV(src, dst) (((src) << TYPLG) + (dst))
Bignum
floatconvert(number
, convto
)
if (number
.num_tag
== convto
)
bp
= &number
.num_uint
[0];
switch(CONV(number
.num_tag
, convto
)){
case CONV(TYPF
, TYPD
): asm("cvtfd (r11), (r11)"); break;
case CONV(TYPF
, TYPG
): mixs
++; break;
case CONV(TYPF
, TYPH
): mixs
++; break;
case CONV(TYPD
, TYPF
): asm("cvtdf (r11), (r11)"); break;
case CONV(TYPD
, TYPG
): mixs
++; break;
case CONV(TYPD
, TYPH
): mixs
++; break;
case CONV(TYPG
, TYPF
): mixs
++; break;
case CONV(TYPG
, TYPD
): mixs
++; break;
case CONV(TYPG
, TYPH
): mixs
++; break;
case CONV(TYPH
, TYPF
): mixs
++; break;
case CONV(TYPH
, TYPD
): mixs
++; break;
case CONV(TYPH
, TYPG
): mixs
++; break;
default: panic("Bad floating point conversion?");
if ((gain
|| mixs
|| loss
) && (passno
== 2)){
yywarning("Converting from %s to %s: %s ",
ty_string
[number
.num_tag
],
gain
? "gains significance" :
(loss
? "looses significance" : "mixs exponent formats")
number
= bignumconvert(number
, convto
, &ovf
);
yywarning("Floating conversion over/underflowed\n");
* Convert a big number between various representations
Bignum
bignumconvert(number
, toconv
, ovfp
)
return(bignumpack(number
, toconv
, ovfp
));
if (toconv
== TYPUNPACKED
){
return(bignumunpack(number
, ovfp
));
return(bignumpack(bignumunpack(number
, ovfp
), toconv
, ovfp
));
Bignum
bignumunpack(Packed
, ovfp
)
reg
struct ty_bigdesc
*p
;
p
= &ty_bigdesc
[Packed
.num_tag
];
mantissa
= CH_FIELD(Mantissa
);
enumber
= CH_FIELD(Enumber
);
packed
= CH_FIELD(Packed
);
Mantissa
.num_tag
= TYPUNPACKED
;
Mantissa
.num_exponent
= MINEXP
;
* map the packed number into the mantissa, using
mapnumber(mantissa
, packed
, 16, p
->b_upmmap
);
* perform the mantissa shifting.
* This may appear to overflow; all that is lost
* is low order bits of the exponent.
(void)numshift(p
->b_mlshift
, mantissa
, mantissa
);
* handle sign and exponent
if (mantissa
[HOC
] & SIGNBIT
){
*ovfp
|= numnegate(mantissa
, mantissa
);
* Normalize the packed by left shifting,
* adjusting the exponent as we go.
* Do a binary weighted left shift for some speed.
for (j
= 4; j
>= 0; --j
){
i
= 1 << j
; /* 16, 8, 4, 2, 1 */
mask
= ONES(i
) << (CH_BITS
- i
);
if (mantissa
[HOC
] & mask
)
(void)numshift(i
, mantissa
, mantissa
);
assert(mantissa
[HOC
] & SIGNBIT
, "integer <<ing");
* now, kick the most significant bit off the top
(void)numshift(1, mantissa
, mantissa
);
* map the exponent into the local area.
mapnumber(enumber
, packed
, 2, p
->b_upemap
);
* Extract the exponent, and get rid
exponent
= Enumber
.num_ushort
[0] & ONES(15);
* shift the exponent, and get rid of high order
exponent
>>= p
->b_ershift
;
exponent
&= ONES(p
->b_esigbits
);
exponent
-= p
->b_eexcess
;
* extract and extend the sign bit
sign
= (Enumber
.num_ushort
[0] & ~ONES(15)) ? -1 : 0;
* Assemble the pieces, and return the number
Mantissa
.num_tag
= TYPUNPACKED
;
Mantissa
.num_sign
= sign
;
Mantissa
.num_exponent
= exponent
;
Bignum
bignumpack(Unpacked
, toconv
, ovfp
)
reg
struct ty_bigdesc
*p
;
if (Unpacked
.num_tag
!= TYPUNPACKED
)
panic("Argument to bignumpack is not unpacked");
enumber
= CH_FIELD(Enumber
);
unpacked
= CH_FIELD(Unpacked
);
exponent
= Unpacked
.num_exponent
;
sign
= Unpacked
.num_sign
;
return(Back
); /* identically zero */
* Put back in the assumed high order fraction
* bit that is always a 1.
(void)numshift(-1, temp
, unpacked
);
if (exponent
> p
->b_eexcess
){
* Construct the largest positive integer
(void)num1comp(temp
, temp
);
* chop the temp; underflow to integer 0
* This will again chop, by shifting
* bits off the right end into oblivion.
for (j
= 4; j
>= 0; --j
){
i
= 1 << j
; /* 16, 8, 4, 2, 1 */
while(exponent
+ i
<= p
->b_eexcess
){
numshift(-i
, temp
, temp
);
* negate the temp if the sign is set
*ovfp
|= numnegate(temp
, temp
);
* Stuff the temp number into the return area
mapnumber(back
, temp
, 16, p
->b_pmmap
);
* Shift the mantissa to the right, filling in zeroes on
* the left. This aligns the least significant bit
* on the bottom of a byte, something that upround
* Put the result into a temporary.
* Even though the shift may be zero, there
* is still a copy involved here.
(void)numshift(-(p
->b_mlshift
), temp
, unpacked
);
* Perform the rounding by adding in 0.5 ulp's
exponent
= upround(&Temp
, p
, exponent
);
* Do a range check on the exponent, in preparation
if ((short)(exponent
+ p
->b_eexcess
) == 0){
* Sorry, no gradual underflow on the
* VAX. Chop this beasty totally to zero
if ((short)(exponent
+ p
->b_eexcess
) < 0){
* True underflow will happen;
* Chop everything to positive zero
sign
= 0; /* avoid reserved operand! */
if ((unsigned)(exponent
+ p
->b_eexcess
)
>= (unsigned)(1 << p
->b_esigbits
)){
* Construct the largest magnitude possible
* floating point unpacked: 0.{1}111111111
(void)num1comp(temp
, temp
);
exponent
= ONES(p
->b_esigbits
);
* Bias it up, and the common code will stuff it.
exponent
+= p
->b_eexcess
;
exponent
<<= p
->b_ershift
;
* mask out trash for the sign, and put in the sign.
Enumber
.num_ushort
[0] = exponent
;
* Map the unpacked exponent into the value going back
mapnumber(back
, enumber
, 2, p
->b_pemap
);
* Stuff the unpacked mantissa into the return area
mapnumber(back
, temp
, 16, p
->b_pmmap
);
mapnumber(chp1
, chp2
, nbytes
, themap
)
for (i
= 0; i
< nbytes
; i
++){
* round in 1/2 ulp in the number, possibly modifying
* the binary exponent if there was total carry out.
* Return the modified exponent
int upround(numberp
, p
, exponent
)
reg
struct ty_bigdesc
*p
;
* Find out the byte index of the byte containing the ulp
number
= CH_FIELD(numberp
[0]);
bytep
= numberp
->num_uchar
;
nbytes
= (p
->b_msigbits
- 1) + p
->b_mlshift
;
assert((nbytes
% 8) == 0, "mantissa sig bits");
assert(byteindex
>= 0, "ulp in outer space");
* Shift the number to the right by two places,
* so that we can do full arithmetic without overflowing
numshift(-UPSHIFT
, number
, number
);
* Construct the missing high order fraction bit
ovfbitindex
= 8 - (p
->b_mlshift
+ UPSHIFT
);
assert(ovfbitindex
>= 0, "Shifted byte 15 into byte 14");
hofractionbit
= (0x01 << ovfbitindex
);
ovffractionbit
= (0x02 << ovfbitindex
);
bytep
[15] |= hofractionbit
;
* construct the unit in the last place, and it
ulp
.num_uchar
[byteindex
] |= (0x80 >> UPSHIFT
);
numaddv(number
, number
, CH_FIELD(ulp
));
ulp
.num_uchar
[byteindex
] &= ~(0x80 >> UPSHIFT
);
* Check if there was an overflow,
* and adjust by shifting.
* Also, bring the number back into canonical
* unpacked form by left shifting by two to undeo
if (bytep
[15] & ovffractionbit
){
numshift(UPSHIFT
- 1, number
, number
);
numshift(UPSHIFT
, number
, number
);
* Clear off trash in the unused bits of the high
* order byte of the number
bytep
[15] &= ONES(8 - p
->b_mlshift
);
printf("Bignum: %s (exp: %d, sign: %d) 0x%08x%08x%08x%08x",
ty_string
[number
.num_tag
],
printf(" == %10.8e", number
.num_num
.numFf_float
.Ff_value
);
printf(" == %20.17e", number
.num_num
.numFd_float
.Fd_value
);
OVF_OVERFLOW
, "cvt overflow",
OVF_UNDERFLOW
, "cvt underflow",
for(i
= 0; ovftab
[i
].which
; i
++){
if (ovf
& ovftab
[i
].which
)
printf("Overflow(%s) ", ovftab
[i
].print
);