cmd/gc: check exponent overflow and underflow in mparith

A too large float constant is an error.
A too small float constant is rounded to zero.

Fixes #7419
Update #6902

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/76730046
This commit is contained in:
Jan Ziak 2014-03-19 05:48:00 +01:00
parent 50f1e1a6b9
commit cb50277510
4 changed files with 63 additions and 8 deletions

View file

@ -1255,6 +1255,7 @@ void mpmovecflt(Mpflt *a, double c);
void mpmulfltflt(Mpflt *a, Mpflt *b);
void mpnegflt(Mpflt *a);
void mpnorm(Mpflt *a);
void mpsetexp(Mpflt *a, int exp);
int mptestflt(Mpflt *a);
int sigfig(Mpflt *a);

View file

@ -416,7 +416,7 @@ mpatoflt(Mpflt *a, char *as)
if(eb) {
if(dp)
goto bad;
a->exp += ex;
mpsetexp(a, a->exp+ex);
goto out;
}
@ -427,8 +427,13 @@ mpatoflt(Mpflt *a, char *as)
mppow10flt(&b, ex-dp);
mpmulfltflt(a, &b);
} else {
mppow10flt(&b, dp-ex);
mpdivfltflt(a, &b);
if((short)(dp-ex) != dp-ex) {
mpmovecflt(a, 0.0);
}
else {
mppow10flt(&b, dp-ex);
mpdivfltflt(a, &b);
}
}
}

View file

@ -22,6 +22,27 @@ sigfig(Mpflt *a)
return i+1;
}
/*
* sets the exponent.
* a too large exponent is an error.
* a too small exponent rounds the number to zero.
*/
void
mpsetexp(Mpflt *a, int exp) {
if((short)exp != exp) {
if(exp > 0) {
yyerror("float constant is too large");
a->exp = 0x7fff;
}
else {
mpmovecflt(a, 0);
}
}
else {
a->exp = exp;
}
}
/*
* shifts the leading non-zero
* word of the number to Mpnorm
@ -60,7 +81,7 @@ mpnorm(Mpflt *a)
}
mpshiftfix(&a->val, s);
a->exp -= s;
mpsetexp(a, a->exp-s);
}
/// implements float arihmetic
@ -95,7 +116,7 @@ mpaddfltflt(Mpflt *a, Mpflt *b)
if(s < 0) {
// b is larger, shift a right
mpshiftfix(&a->val, s);
a->exp -= s;
mpsetexp(a, a->exp-s);
mpaddfixfix(&a->val, &b->val, 0);
goto out;
}
@ -131,7 +152,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b)
}
mpmulfract(&a->val, &b->val);
a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
mpnorm(a);
if(Mpdebug)
@ -171,7 +192,7 @@ mpdivfltflt(Mpflt *a, Mpflt *b)
// divide
mpdivfract(&a->val, &c.val);
a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1;
mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
mpnorm(a);
if(Mpdebug)
@ -199,7 +220,10 @@ mpgetflt(Mpflt *a)
while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
mpshiftfix(&a->val, 1);
a->exp -= 1;
mpsetexp(a, a->exp-1); // can set 'a' to zero
s = sigfig(a);
if(s == 0)
return 0;
}
// the magic numbers (64, 63, 53, 10, -1074) are

View file

@ -0,0 +1,25 @@
// run
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 7419: odd behavior for float constants underflowing to 0
package main
import (
"os"
)
var x = 1e-779137
var y = 1e-779138
func main() {
if x != 0 {
os.Exit(1)
}
if y != 0 {
os.Exit(2)
}
}