- Use BN_set_negative() and BN_is_negative() instead of subtracting or
comparing to zero. - Fix fractional number exponentiation, especially for negative exponents. Obtained from: OpenBSD
This commit is contained in:
parent
2befb3613f
commit
c3761c3848
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=244861
@ -29,8 +29,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include "extern.h"
|
#include "extern.h"
|
||||||
|
|
||||||
BIGNUM zero;
|
|
||||||
|
|
||||||
#define __inline
|
#define __inline
|
||||||
|
|
||||||
#define MAX_ARRAY_INDEX 2048
|
#define MAX_ARRAY_INDEX 2048
|
||||||
@ -250,8 +248,12 @@ init_bmachine(bool extended_registers)
|
|||||||
if (bmachine.readstack == NULL)
|
if (bmachine.readstack == NULL)
|
||||||
err(1, NULL);
|
err(1, NULL);
|
||||||
bmachine.obase = bmachine.ibase = 10;
|
bmachine.obase = bmachine.ibase = 10;
|
||||||
BN_init(&zero);
|
}
|
||||||
bn_check(BN_zero(&zero));
|
|
||||||
|
u_int
|
||||||
|
bmachine_scale(void)
|
||||||
|
{
|
||||||
|
return (bmachine.scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the things needed before processing a (new) file */
|
/* Reset the things needed before processing a (new) file */
|
||||||
@ -407,7 +409,7 @@ split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__inline void
|
void
|
||||||
normalize(struct number *n, u_int s)
|
normalize(struct number *n, u_int s)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -427,7 +429,7 @@ void
|
|||||||
negate(struct number *n)
|
negate(struct number *n)
|
||||||
{
|
{
|
||||||
|
|
||||||
bn_check(BN_sub(n->number, &zero, n->number));
|
BN_set_negative(n->number, !BN_is_negative(n->number));
|
||||||
}
|
}
|
||||||
|
|
||||||
static __inline void
|
static __inline void
|
||||||
@ -581,7 +583,7 @@ set_scale(void)
|
|||||||
|
|
||||||
n = pop_number();
|
n = pop_number();
|
||||||
if (n != NULL) {
|
if (n != NULL) {
|
||||||
if (BN_cmp(n->number, &zero) < 0)
|
if (BN_is_negative(n->number))
|
||||||
warnx("scale must be a nonnegative number");
|
warnx("scale must be a nonnegative number");
|
||||||
else {
|
else {
|
||||||
scale = get_ulong(n);
|
scale = get_ulong(n);
|
||||||
@ -878,7 +880,7 @@ load_array(void)
|
|||||||
if (inumber == NULL)
|
if (inumber == NULL)
|
||||||
return;
|
return;
|
||||||
idx = get_ulong(inumber);
|
idx = get_ulong(inumber);
|
||||||
if (BN_cmp(inumber->number, &zero) < 0)
|
if (BN_is_negative(inumber->number))
|
||||||
warnx("negative idx");
|
warnx("negative idx");
|
||||||
else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX)
|
else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX)
|
||||||
warnx("idx too big");
|
warnx("idx too big");
|
||||||
@ -917,7 +919,7 @@ store_array(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
idx = get_ulong(inumber);
|
idx = get_ulong(inumber);
|
||||||
if (BN_cmp(inumber->number, &zero) < 0) {
|
if (BN_is_negative(inumber->number)) {
|
||||||
warnx("negative idx");
|
warnx("negative idx");
|
||||||
stack_free_value(value);
|
stack_free_value(value);
|
||||||
} else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) {
|
} else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) {
|
||||||
@ -1009,7 +1011,7 @@ bsub(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bmul_number(struct number *r, struct number *a, struct number *b)
|
bmul_number(struct number *r, struct number *a, struct number *b, u_int scale)
|
||||||
{
|
{
|
||||||
BN_CTX *ctx;
|
BN_CTX *ctx;
|
||||||
|
|
||||||
@ -1023,11 +1025,9 @@ bmul_number(struct number *r, struct number *a, struct number *b)
|
|||||||
bn_check(BN_mul(r->number, a->number, b->number, ctx));
|
bn_check(BN_mul(r->number, a->number, b->number, ctx));
|
||||||
BN_CTX_free(ctx);
|
BN_CTX_free(ctx);
|
||||||
|
|
||||||
if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) {
|
r->scale = rscale;
|
||||||
r->scale = rscale;
|
if (rscale > bmachine.scale && rscale > ascale && rscale > bscale)
|
||||||
normalize(r, max(bmachine.scale, max(ascale, bscale)));
|
normalize(r, max(scale, max(ascale, bscale)));
|
||||||
} else
|
|
||||||
r->scale = rscale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1046,7 +1046,7 @@ bmul(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
r = new_number();
|
r = new_number();
|
||||||
bmul_number(r, a, b);
|
bmul_number(r, a, b, bmachine.scale);
|
||||||
|
|
||||||
push_number(r);
|
push_number(r);
|
||||||
free_number(a);
|
free_number(a);
|
||||||
@ -1172,7 +1172,7 @@ static void
|
|||||||
bexp(void)
|
bexp(void)
|
||||||
{
|
{
|
||||||
struct number *a, *p, *r;
|
struct number *a, *p, *r;
|
||||||
u_int scale;
|
u_int rscale;
|
||||||
bool neg;
|
bool neg;
|
||||||
|
|
||||||
p = pop_number();
|
p = pop_number();
|
||||||
@ -1185,15 +1185,27 @@ bexp(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->scale != 0)
|
if (p->scale != 0) {
|
||||||
warnx("Runtime warning: non-zero scale in exponent");
|
BIGNUM *i, *f;
|
||||||
|
i = BN_new();
|
||||||
|
bn_checkp(i);
|
||||||
|
f = BN_new();
|
||||||
|
bn_checkp(f);
|
||||||
|
split_number(p, i, f);
|
||||||
|
if (!BN_is_zero(f))
|
||||||
|
warnx("Runtime warning: non-zero fractional part "
|
||||||
|
"in exponent");
|
||||||
|
BN_free(i);
|
||||||
|
BN_free(f);
|
||||||
|
}
|
||||||
|
|
||||||
normalize(p, 0);
|
normalize(p, 0);
|
||||||
|
|
||||||
neg = false;
|
neg = false;
|
||||||
if (BN_cmp(p->number, &zero) < 0) {
|
if (BN_is_negative(p->number)) {
|
||||||
neg = true;
|
neg = true;
|
||||||
negate(p);
|
negate(p);
|
||||||
scale = bmachine.scale;
|
rscale = bmachine.scale;
|
||||||
} else {
|
} else {
|
||||||
/* Posix bc says min(a.scale * b, max(a.scale, scale) */
|
/* Posix bc says min(a.scale * b, max(a.scale, scale) */
|
||||||
u_long b;
|
u_long b;
|
||||||
@ -1201,30 +1213,37 @@ bexp(void)
|
|||||||
|
|
||||||
b = BN_get_word(p->number);
|
b = BN_get_word(p->number);
|
||||||
m = max(a->scale, bmachine.scale);
|
m = max(a->scale, bmachine.scale);
|
||||||
scale = a->scale * (u_int)b;
|
rscale = a->scale * (u_int)b;
|
||||||
if (scale > m || (a->scale > 0 && (b == BN_MASK2 ||
|
if (rscale > m || (a->scale > 0 && (b == BN_MASK2 ||
|
||||||
b > UINT_MAX)))
|
b > UINT_MAX)))
|
||||||
scale = m;
|
rscale = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BN_is_zero(p->number)) {
|
if (BN_is_zero(p->number)) {
|
||||||
r = new_number();
|
r = new_number();
|
||||||
bn_check(BN_one(r->number));
|
bn_check(BN_one(r->number));
|
||||||
normalize(r, scale);
|
normalize(r, rscale);
|
||||||
} else {
|
} else {
|
||||||
|
u_int ascale, mscale;
|
||||||
|
|
||||||
|
ascale = a->scale;
|
||||||
while (!BN_is_bit_set(p->number, 0)) {
|
while (!BN_is_bit_set(p->number, 0)) {
|
||||||
bmul_number(a, a, a);
|
ascale *= 2;
|
||||||
|
bmul_number(a, a, a, ascale);
|
||||||
bn_check(BN_rshift1(p->number, p->number));
|
bn_check(BN_rshift1(p->number, p->number));
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dup_number(a);
|
r = dup_number(a);
|
||||||
normalize(r, scale);
|
|
||||||
bn_check(BN_rshift1(p->number, p->number));
|
bn_check(BN_rshift1(p->number, p->number));
|
||||||
|
|
||||||
|
mscale = ascale;
|
||||||
while (!BN_is_zero(p->number)) {
|
while (!BN_is_zero(p->number)) {
|
||||||
bmul_number(a, a, a);
|
ascale *= 2;
|
||||||
if (BN_is_bit_set(p->number, 0))
|
bmul_number(a, a, a, ascale);
|
||||||
bmul_number(r, r, a);
|
if (BN_is_bit_set(p->number, 0)) {
|
||||||
|
mscale += ascale;
|
||||||
|
bmul_number(r, r, a, mscale);
|
||||||
|
}
|
||||||
bn_check(BN_rshift1(p->number, p->number));
|
bn_check(BN_rshift1(p->number, p->number));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1237,13 +1256,18 @@ bexp(void)
|
|||||||
bn_check(BN_one(one));
|
bn_check(BN_one(one));
|
||||||
ctx = BN_CTX_new();
|
ctx = BN_CTX_new();
|
||||||
bn_checkp(ctx);
|
bn_checkp(ctx);
|
||||||
scale_number(one, r->scale + scale);
|
scale_number(one, r->scale + rscale);
|
||||||
normalize(r, scale);
|
|
||||||
bn_check(BN_div(r->number, NULL, one, r->number, ctx));
|
if (BN_is_zero(r->number))
|
||||||
|
warnx("divide by zero");
|
||||||
|
else
|
||||||
|
bn_check(BN_div(r->number, NULL, one,
|
||||||
|
r->number, ctx));
|
||||||
BN_free(one);
|
BN_free(one);
|
||||||
BN_CTX_free(ctx);
|
BN_CTX_free(ctx);
|
||||||
|
r->scale = rscale;
|
||||||
} else
|
} else
|
||||||
normalize(r, scale);
|
normalize(r, rscale);
|
||||||
}
|
}
|
||||||
push_number(r);
|
push_number(r);
|
||||||
free_number(a);
|
free_number(a);
|
||||||
@ -1282,7 +1306,7 @@ bsqrt(void)
|
|||||||
if (BN_is_zero(n->number)) {
|
if (BN_is_zero(n->number)) {
|
||||||
r = new_number();
|
r = new_number();
|
||||||
push_number(r);
|
push_number(r);
|
||||||
} else if (BN_cmp(n->number, &zero) < 0)
|
} else if (BN_is_negative(n->number))
|
||||||
warnx("square root of negative number");
|
warnx("square root of negative number");
|
||||||
else {
|
else {
|
||||||
scale = max(bmachine.scale, n->scale);
|
scale = max(bmachine.scale, n->scale);
|
||||||
|
@ -85,6 +85,7 @@ struct source {
|
|||||||
|
|
||||||
void init_bmachine(bool);
|
void init_bmachine(bool);
|
||||||
void reset_bmachine(struct source *);
|
void reset_bmachine(struct source *);
|
||||||
|
u_int bmachine_scale(void);
|
||||||
void scale_number(BIGNUM *, int);
|
void scale_number(BIGNUM *, int);
|
||||||
void normalize(struct number *, u_int);
|
void normalize(struct number *, u_int);
|
||||||
void eval(void);
|
void eval(void);
|
||||||
@ -93,6 +94,4 @@ void pbn(const char *, const BIGNUM *);
|
|||||||
void negate(struct number *);
|
void negate(struct number *);
|
||||||
void split_number(const struct number *, BIGNUM *, BIGNUM *);
|
void split_number(const struct number *, BIGNUM *, BIGNUM *);
|
||||||
void bmul_number(struct number *, struct number *,
|
void bmul_number(struct number *, struct number *,
|
||||||
struct number *);
|
struct number *, u_int);
|
||||||
|
|
||||||
extern BIGNUM zero;
|
|
||||||
|
@ -322,7 +322,7 @@ printnumber(FILE *f, const struct number *b, u_int base)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
sz = i;
|
sz = i;
|
||||||
if (BN_cmp(b->number, &zero) < 0)
|
if (BN_is_negative(b->number))
|
||||||
putcharwrap(f, '-');
|
putcharwrap(f, '-');
|
||||||
for (i = 0; i < sz; i++) {
|
for (i = 0; i < sz; i++) {
|
||||||
p = stack_popstring(&stack);
|
p = stack_popstring(&stack);
|
||||||
@ -353,7 +353,8 @@ printnumber(FILE *f, const struct number *b, u_int base)
|
|||||||
putcharwrap(f, ' ');
|
putcharwrap(f, ' ');
|
||||||
i = 1;
|
i = 1;
|
||||||
|
|
||||||
bmul_number(fract_part, fract_part, num_base);
|
bmul_number(fract_part, fract_part, num_base,
|
||||||
|
bmachine_scale());
|
||||||
split_number(fract_part, int_part->number, NULL);
|
split_number(fract_part, int_part->number, NULL);
|
||||||
rem = BN_get_word(int_part->number);
|
rem = BN_get_word(int_part->number);
|
||||||
p = get_digit(rem, digits, base);
|
p = get_digit(rem, digits, base);
|
||||||
@ -402,8 +403,8 @@ print_ascii(FILE *f, const struct number *n)
|
|||||||
v = BN_dup(n->number);
|
v = BN_dup(n->number);
|
||||||
bn_checkp(v);
|
bn_checkp(v);
|
||||||
|
|
||||||
if (BN_cmp(v, &zero) < 0)
|
if (BN_is_negative(v))
|
||||||
bn_check(BN_sub(v, &zero, v));
|
BN_set_negative(v, 0);
|
||||||
|
|
||||||
numbits = BN_num_bytes(v) * 8;
|
numbits = BN_num_bytes(v) * 8;
|
||||||
while (numbits > 0) {
|
while (numbits > 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user