Skip to content

Commit 15892da

Browse files
committed
Correct EVEN? and ODD? for decimals.
Optimize and simplify integer ADD. Optimize and simplify integer SUBTRACT. Optimize and simplify integer MULTIPLY. Generalize integer DIVIDE. Generalize integer NEGATE. Generalize and optimize integer ABS.
1 parent 484526b commit 15892da

File tree

2 files changed

+69
-50
lines changed

2 files changed

+69
-50
lines changed

src/core/t-decimal.c

+17-15
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,22 @@ static char *gcvt(double value, int digits, char *buffer)
4545

4646
/*
4747
Purpose: {defines the almost_equal comparison function}
48-
Properties: {
48+
Properties: {
4949
since floating point numbers are ordered and there is only
5050
a finite quantity of floating point numbers, it is possible
5151
to assign an ordinal (integer) number to any floating point number so,
5252
that the ordinal numbers of neighbors differ by one
53-
53+
5454
the function compares floating point numbers based on
5555
the difference of their ordinal numbers in the ordering
5656
of floating point numbers
57-
57+
5858
difference of 0 means exact equality, difference of 1 means, that
5959
the numbers are neighbors.
6060
}
6161
Advantages: {
6262
the function detects approximate equality.
63-
63+
6464
the function is more strict in the zero neighborhood than
6565
absolute-error-based approaches
6666
@@ -69,15 +69,15 @@ static char *gcvt(double value, int digits, char *buffer)
6969
meaning that neighbors are deemed equal, max_diff = 10 meaning, that
7070
the numbers are deemed equal if at most 9
7171
distinct floating point numbers can be found between them
72-
72+
7373
the max_diff value may be one of the system options specified in
7474
the system/options object allowing users to exactly define the
7575
strictness of equality checks
7676
}
7777
Differences: {
7878
The approximate comparison currently used in R3 corresponds to the
7979
almost_equal function using max_diff = 10 (according to my tests).
80-
80+
8181
The main differences between the currently used comparison and the
8282
one based on the ordinal number comparison are:
8383
- the max_diff parameter can be adjusted, allowing
@@ -106,7 +106,7 @@ REBOOL almost_equal(REBDEC a, REBDEC b, REBCNT max_diff) {
106106

107107
int_diff = ua.i - ub.i;
108108
if (int_diff < 0) int_diff = -int_diff;
109-
109+
110110
return ((REBU64) int_diff <= max_diff);
111111
}
112112

@@ -316,13 +316,15 @@ REBOOL almost_equal(REBDEC a, REBDEC b, REBCNT max_diff) {
316316
case A_NEGATE:
317317
d1 = -d1;
318318
goto setDec;
319+
319320
case A_ABSOLUTE:
320321
if (d1 < 0) d1 = -d1;
321322
goto setDec;
323+
322324
case A_EVENQ:
323325
case A_ODDQ:
324326
d1 = fabs(fmod(d1, 2.0));
325-
DECIDE((action != A_EVENQ) != ((d1 < 0.5) || (d1 >= 1.5)));
327+
DECIDE((action == A_EVENQ) == (d1 < -1.5 || d1 > 1.5 || (d1 > -0.5 && d1 < 0.5)));
326328

327329
case A_MAKE:
328330
case A_TO:
@@ -341,23 +343,23 @@ REBOOL almost_equal(REBDEC a, REBDEC b, REBCNT max_diff) {
341343
case REB_PERCENT:
342344
d1 = VAL_DECIMAL(val);
343345
goto setDec;
344-
346+
345347
case REB_INTEGER:
346348
d1 = (REBDEC)VAL_INT64(val);
347349
goto setDec;
348-
350+
349351
case REB_MONEY:
350352
d1 = deci_to_decimal(VAL_DECI(val));
351353
goto setDec;
352-
354+
353355
case REB_LOGIC:
354356
d1 = VAL_LOGIC(val) ? 1.0 : 0.0;
355357
goto setDec;
356-
358+
357359
case REB_CHAR:
358360
d1 = (REBDEC)VAL_CHAR(val);
359361
goto setDec;
360-
362+
361363
case REB_TIME:
362364
d1 = VAL_TIME(val) * NANO;
363365
break;
@@ -374,12 +376,12 @@ REBOOL almost_equal(REBDEC a, REBDEC b, REBCNT max_diff) {
374376
}
375377
Trap_Make(type, val);
376378
}
377-
379+
378380
case REB_BINARY:
379381
Binary_To_Decimal(val, D_RET);
380382
d1 = VAL_DECIMAL(D_RET);
381383
break;
382-
384+
383385
#ifdef removed
384386
// case REB_ISSUE:
385387
{

src/core/t-integer.c

+52-35
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,8 @@
5555
REBI64 arg;
5656
REBINT n;
5757

58-
REBU64 p, a, b; // for overflow detection
59-
REBCNT a1, a0, b1, b0;
58+
REBU64 a1, a0, b1, b0;
6059
REBFLG sgn;
61-
REBI64 anum;
6260

6361
num = VAL_INT64(val);
6462

@@ -110,46 +108,62 @@
110108
switch (action) {
111109

112110
case A_ADD:
113-
anum = (REBU64)num + (REBU64)arg;
114-
if (
115-
((num < 0) == (arg < 0)) && ((num < 0) != (anum < 0))
116-
) Trap0(RE_OVERFLOW);
117-
num = anum;
111+
if(num >= 0) {
112+
if(arg > MAX_I64 - num)
113+
Trap0(RE_OVERFLOW);
114+
} else {
115+
if(arg < MIN_I64 - num)
116+
Trap0(RE_OVERFLOW);
117+
}
118+
num += arg;
118119
break;
119120

120121
case A_SUBTRACT:
121-
anum = (REBU64)num - (REBU64)arg;
122-
if (
123-
((num < 0) != (arg < 0)) && ((num < 0) != (anum < 0))
124-
) Trap0(RE_OVERFLOW);
125-
num = anum;
122+
if(arg >= 0) {
123+
if(num < MIN_I64 + arg)
124+
Trap0(RE_OVERFLOW);
125+
} else {
126+
if(num > MAX_I64 + arg)
127+
Trap0(RE_OVERFLOW);
128+
}
129+
num -= arg;
126130
break;
127131

128132
case A_MULTIPLY:
129-
a = num;
130-
sgn = (num < 0);
131-
if (sgn) a = -a;
132-
b = arg;
133-
if (arg < 0) {
133+
// handle signs
134+
sgn = num < 0;
135+
if(sgn)
136+
num = -(REBU64) num;
137+
if(arg < 0) {
134138
sgn = !sgn;
135-
b = -b;
139+
arg = -(REBU64) arg;
136140
}
137-
p = a * b;
138-
a1 = a>>32;
139-
a0 = a;
140-
b1 = b>>32;
141-
b0 = b;
142-
if (
143-
(a1 && b1)
144-
|| ((REBU64)a0 * b1 + (REBU64)a1 * b0 > p >> 32)
145-
|| ((p > (REBU64)MAX_I64) && (!sgn || (p > -(REBU64)MIN_I64)))
146-
) Trap0(RE_OVERFLOW);
147-
num = sgn ? -p : p;
141+
// subdivide the factors
142+
a1 = (REBU64) num >> 32;
143+
b1 = (REBU64) arg >> 32;
144+
a0 = (REBU64) num & 0xFFFFFFFFu;
145+
b0 = (REBU64) arg & 0xFFFFFFFFu;
146+
// multiply the parts
147+
if(!a1)
148+
num = b1 * a0;
149+
else if(!b1)
150+
num = a1 * b0;
151+
else
152+
Trap0(RE_OVERFLOW);
153+
if((REBU64) num > (REBU64) MIN_I64 >> 32)
154+
Trap0(RE_OVERFLOW);
155+
num = ((REBU64) num << 32) + a0 * b0;
156+
if(sgn) {
157+
if((REBU64) num > (REBU64) MIN_I64)
158+
Trap0(RE_OVERFLOW);
159+
num = -(REBU64) num;
160+
} else if((REBU64) num > (REBU64) MAX_I64)
161+
Trap0(RE_OVERFLOW);
148162
break;
149163

150164
case A_DIVIDE:
151165
if (arg == 0) Trap0(RE_ZERO_DIVIDE);
152-
if (num == MIN_I64 && arg == -1) Trap0(RE_OVERFLOW);
166+
if (num < - MAX_I64 && arg == -1) Trap0(RE_OVERFLOW);
153167
if (num % arg == 0) {
154168
num = num / arg;
155169
break;
@@ -171,15 +185,18 @@
171185
case A_XOR: num ^= arg; break;
172186

173187
case A_NEGATE:
174-
if (num == MIN_I64) Trap0(RE_OVERFLOW);
188+
if (num < - MAX_I64) Trap0(RE_OVERFLOW);
175189
num = -num;
176190
break;
177191

178192
case A_COMPLEMENT: num = ~num; break;
179193

180-
case A_ABSOLUTE:
181-
if (num == MIN_I64) Trap0(RE_OVERFLOW);
182-
if (num < 0) num = -num;
194+
case A_ABSOLUTE:
195+
if(num < 0) {
196+
if (num < - MAX_I64)
197+
Trap0(RE_OVERFLOW);
198+
num = -num;
199+
}
183200
break;
184201

185202
case A_EVENQ: num = ~num;

0 commit comments

Comments
 (0)