shithub: femtolisp

Download patch

ref: ef7ebf3be36e594d802d555cde11913e26b3d468
parent: 73063b8a1eb2647abff04cd4af49d04239a5222a
author: mag <mag-one@autistici.org>
date: Fri Jun 23 12:36:23 EDT 2023

fl_add_any: initial overflow handling

--- a/cvalues.c
+++ b/cvalues.c
@@ -1,4 +1,5 @@
 #include "operators.c"
+#include "overflows.h"
 
 #ifdef BITS64
 #define NWORDS(sz) (((sz)+7)>>3)
@@ -974,7 +975,9 @@
 fl_add_any(value_t *args, uint32_t nargs, fixnum_t carryIn)
 {
 	uint64_t Uaccum = 0;
+	uint64_t Uresult = 0;
 	int64_t Saccum = carryIn;
+	int64_t Sresult = 0;
 	double Faccum = 0;
 	int32_t inexact = 0;
 	uint32_t i;
@@ -1000,12 +1003,36 @@
 			case T_UINT32: Uaccum += *(uint32_t*)a; break;
 			case T_INT64:
 				i64 = *(int64_t*)a;
-				if(i64 > 0)
-					Uaccum += (uint64_t)i64;
-				else
-					Saccum += i64;
+				if(i64 > 0){
+					if(addof_uint64(Uresult, Uaccum, (uint64_t)i64)){
+						if(Maccum == nil)
+							Maccum = mpnew(0);
+						x = uvtomp((uint64_t)i64, nil);
+						mpadd(Maccum, x, Maccum);
+						mpfree(x);
+					}else
+						Uaccum = Uresult;
+				}else{
+					if(subof_int64(Sresult, Saccum, i64)){
+						if(Maccum == nil)
+							Maccum = mpnew(0);
+						x = vtomp(i64, nil);
+						mpadd(Maccum, x, Maccum);
+						mpfree(x);
+					}else
+						Saccum += i64;
+				}
 				break;
-			case T_UINT64: Uaccum += *(uint64_t*)a; break;
+			case T_UINT64:
+				if(addof_uint64(Uresult, Uaccum, *(uint64_t*)a)){
+					if(Maccum == nil)
+						Maccum = mpnew(0);
+					x = uvtomp(*(uint64_t*)a, nil);
+					mpadd(Maccum, x, Maccum);
+					mpfree(x);
+				}else
+					Uaccum = Uresult;
+				break;
 			case T_MPINT:
 				if(Maccum == nil)
 					Maccum = mpnew(0);
@@ -1056,9 +1083,18 @@
 		}
 		Uaccum -= negpart;
 	}else{
-		Uaccum += (uint64_t)Saccum;
+		if(addof_uint64(Uresult, Uaccum, (uint64_t)Saccum)){
+			if(Maccum == nil)
+				Maccum = mpnew(0);
+			x = vtomp(Saccum, nil);
+			mpadd(Maccum, x, Maccum);
+			x = uvtomp(Uaccum, x);
+			mpadd(Maccum, x, Maccum);
+			mpfree(x);
+			return mk_mpint(Maccum);
+		}else
+			Uaccum = Uresult;
 	}
-	// return value in Uaccum
 	return return_from_uint64(Uaccum);
 }
 
--- a/overflows.h
+++ b/overflows.h
@@ -11,13 +11,9 @@
   ((INT64_MIN+(b) <= (a))?((c=(a)-(b))?0:1):1) \
 )
 
-#define mulof_int64(c,a,b) ( \
-  (((a) != 0) && ((c=(a)*(b))/(a) != (b)))?1:0 \
-)
-
 #define addof_uint64(c,a,b) ( \
   (b < 1)? \
-  ((0-(b) <= (a))?((c=(a)+(b))?0:1):1): \
+  ((-(b) <= (a))?((c=(a)+(b))?0:1):1): \
   ((UINT64_MAX-(b) >= (a))?((c=(a)+(b))?0:1):1) \
 )
 
@@ -27,7 +23,7 @@
   (((b) <= (a))?((c=(a)-(b))?0:1):1) \
 )
 
-#define mulof_uint64(c,a,b) ( \
+#define mulof(c,a,b) ( \
   (((a) != 0) && ((c=(a)*(b))/(a) != (b)))?1:0 \
 )
 
--- a/test/number-boundaries.lsp
+++ b/test/number-boundaries.lsp
@@ -36,24 +36,62 @@
 (princ "uint64 : " (number-borders uint64) "\n")
 (princ "---\n")
 
+; add/sub signed
 (assert (= 128 (+ (high-border int8) 1)))
+(assert (= 128 (+ 1 (high-border int8))))
 (assert (= -129 (- (low-border int8) 1)))
+(assert (= 129 (- 1 (low-border int8))))
 (assert (= 32768 (+ (high-border int16) 1)))
+(assert (= 32768 (+ 1 (high-border int16))))
 (assert (= -32769 (- (low-border int16) 1)))
+(assert (= 32769 (- 1 (low-border int16))))
 (assert (= 2147483648 (+ (high-border int32) 1)))
+(assert (= 2147483648 (+ 1 (high-border int32))))
 (assert (= -2147483649 (- (low-border int32) 1)))
+(assert (= 2147483649 (- 1 (low-border int32))))
 (assert (= 9223372036854775808 (+ (high-border int64) 1)))
-;(assert (= -9223372036854775809 (- (low-border int64) 1))) ;OVERFLOW
+(assert (= 9223372036854775808 (+ 1 (high-border int64))))
+(assert (= -9223372036854775809 (- (low-border int64) 1)))
+(assert (= 9223372036854775809 (- 1 (low-border int64))))
+(assert (= 27670116110564327421 (+ 9223372036854775807 9223372036854775807 9223372036854775807)))
+(assert (= -12297829382473033728 (+ -3074457345618258432 -3074457345618258432 -3074457345618258432 -3074457345618258432)))
+(assert (= 6148914691236516864 (- -3074457345618258432 -3074457345618258432 -3074457345618258432 -3074457345618258432)))
 
+; add/sub unsigned
 (assert (= 256 (+ (high-border uint8) 1)))
+(assert (= 256 (+ 1 (high-border uint8))))
 (assert (= -1 (- (low-border uint8) 1)))
+(assert (= 1 (- 1 (low-border uint8))))
 (assert (= 65536 (+ (high-border uint16) 1)))
+(assert (= 65536 (+ 1 (high-border uint16))))
 (assert (= -1 (- (low-border uint16) 1)))
+(assert (= 1 (- 1 (low-border uint16))))
 (assert (= 4294967296 (+ (high-border uint32) 1)))
+(assert (= 4294967296 (+ 1 (high-border uint32))))
 (assert (= -1 (- (low-border uint32) 1)))
-;(assert (= 18446744073709551616 (+ (high-border uint64) 1))) ;OVERFLOW
+(assert (= 1 (- 1 (low-border uint32))))
+(assert (= 18446744073709551616 (+ (high-border uint64) 1)))
+(assert (= 18446744073709551616 (+ 1 (high-border uint64))))
+(assert (= 36893488147419103230 (+ (high-border uint64) (high-border uint64))))
+(assert (= 36893488147419103231 (+ 1 (high-border uint64) (high-border uint64))))
+(assert (= 36893488147419103231 (+ (high-border uint64) 1 (high-border uint64))))
+(assert (= 36893488147419103231 (+ (high-border uint64) (high-border uint64) 1)))
 (assert (= -1 (- (low-border uint64) 1)))
+(assert (= 1 (- 1 (low-border uint64))))
 
-(princ "all tests pass\n\n")
+; mul signed
+(assert (= 18446744073709551614 (* (high-border int64) 2)))
+;(assert (= -18446744073709551614 (* (high-border int64) -2)))
+(assert (= 18446744073709551614 (* 2 (high-border int64))))
+;(assert (= -18446744073709551616 (* (low-border int64) 2)))
+;(assert (= -18446744073709551616 (* 2 (low-border int64))))
+
+; mul unsigned
+;(assert (= 36893488147419103230 (* (high-border uint64) 2)))
+;(assert (= 36893488147419103230 (* 2 (high-border uint64))))
+;(assert (= -36893488147419103230 (* (high-border uint64) -2)))
+;(assert (= -36893488147419103230 (* -2 (high-border uint64))))
+
+(princ "all number boundaries tests pass\n\n")
 #t
 
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -82,11 +82,14 @@
 
 (assert (> 9223372036854775808 9223372036854775807))
 
+; number boundaries
+(load "number-boundaries.lsp")
+
 ; bignum
 (assert (> 0x10000000000000000 0x8fffffffffffffff))
 (assert (< 0x8fffffffffffffff 0x10000000000000000))
 
-(assert ((not bignum? (ash 2 60))))
+(assert (not (bignum? (ash 2 60))))
 (assert (not (bignum? (- (ash 2 60) 1))))
 (assert (bignum? 1606938044258990275541962092341162602522202993782792835301376))
 (assert (bignum? 0xfffffffffffffffff))