From 341f92f1228e13c0d49ef1c5ba06f8fbc8d4eae4 Mon Sep 17 00:00:00 2001
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
Date: Sun, 22 Dec 2019 23:35:39 +0400
Subject: [PATCH] Fixed factorial calculation on 64-bit windows

---
 .../misc/combin/cl_I_doublefactorial.cc       | 66 +++++++++----------
 src/integer/misc/combin/cl_I_factorial.cc     | 40 +++++------
 tests/Makefile.am                             |  1 +
 tests/test_I.cc                               |  4 ++
 tests/test_I_factorial.cc                     | 15 +++++
 5 files changed, 73 insertions(+), 53 deletions(-)
 create mode 100644 tests/test_I_factorial.cc

diff --git a/src/integer/misc/combin/cl_I_doublefactorial.cc b/src/integer/misc/combin/cl_I_doublefactorial.cc
index 74acc91..b811632 100644
--- a/src/integer/misc/combin/cl_I_doublefactorial.cc
+++ b/src/integer/misc/combin/cl_I_doublefactorial.cc
@@ -30,68 +30,68 @@ const cl_I doublefactorial (uintL n) // assume n >= 0 small
 {
 	static cl_I const doublefakul_table [] = {
         1,
-        1UL,
-        1UL*2,
-        1UL*3,
+        UINT64_C(1),
+        UINT64_C(1)*2,
+        UINT64_C(1)*3,
         #if (cl_value_len>=5)
-        1UL*2*4,
-        1UL*3*5,
+        UINT64_C(1)*2*4,
+        UINT64_C(1)*3*5,
         #if (cl_value_len>=7)
-        1UL*2*4*6,
+        UINT64_C(1)*2*4*6,
         #if (cl_value_len>=8)
-        1UL*3*5*7,
+        UINT64_C(1)*3*5*7,
         #if (cl_value_len>=10)
-        1UL*2*4*6*8,
+        UINT64_C(1)*2*4*6*8,
         #if (cl_value_len>=11)
-        1UL*3*5*7*9,
+        UINT64_C(1)*3*5*7*9,
         #if (cl_value_len>=13)
-        1UL*2*4*6*8*10,
+        UINT64_C(1)*2*4*6*8*10,
         #if (cl_value_len>=15)
-        1UL*3*5*7*9*11,
+        UINT64_C(1)*3*5*7*9*11,
         #if (cl_value_len>=17)
-        1UL*2*4*6*8*10*12,
+        UINT64_C(1)*2*4*6*8*10*12,
         #if (cl_value_len>=19)
-        1UL*3*5*7*9*11*13,
+        UINT64_C(1)*3*5*7*9*11*13,
         #if (cl_value_len>=21)
-        1UL*2*4*6*8*10*12*14,
+        UINT64_C(1)*2*4*6*8*10*12*14,
         #if (cl_value_len>=22)
-        1UL*3*5*7*9*11*13*15,
+        UINT64_C(1)*3*5*7*9*11*13*15,
         #if (cl_value_len>=25)
-        1UL*2*4*6*8*10*12*14*16,
+        UINT64_C(1)*2*4*6*8*10*12*14*16,
         #if (cl_value_len>=27)
-        1UL*3*5*7*9*11*13*15*17,
+        UINT64_C(1)*3*5*7*9*11*13*15*17,
         #if (cl_value_len>=29)
-        1UL*2*4*6*8*10*12*14*16*18,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18,
         #if (cl_value_len>=31)
-        1UL*3*5*7*9*11*13*15*17*19,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19,
         #if (cl_value_len>=33)
-        1UL*2*4*6*8*10*12*14*16*18*20,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18*20,
         #if (cl_value_len>=35)
-        1UL*3*5*7*9*11*13*15*17*19*21,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19*21,
         #if (cl_value_len>=38)
-        1UL*2*4*6*8*10*12*14*16*18*20*22,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18*20*22,
         #if (cl_value_len>=40)
-        1UL*3*5*7*9*11*13*15*17*19*21*23,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19*21*23,
         #if (cl_value_len>=42)
-        1UL*2*4*6*8*10*12*14*16*18*20*22*24,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18*20*22*24,
         #if (cl_value_len>=44)
-        1UL*3*5*7*9*11*13*15*17*19*21*23*25,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19*21*23*25,
         #if (cl_value_len>=47)
-        1UL*2*4*6*8*10*12*14*16*18*20*22*24*26,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18*20*22*24*26,
         #if (cl_value_len>=49)
-        1UL*3*5*7*9*11*13*15*17*19*21*23*25*27,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19*21*23*25*27,
         #if (cl_value_len>=52)
-        1UL*2*4*6*8*10*12*14*16*18*20*22*24*26*28,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18*20*22*24*26*28,
         #if (cl_value_len>=54)
-        1UL*3*5*7*9*11*13*15*17*19*21*23*25*27*29,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19*21*23*25*27*29,
         #if (cl_value_len>=57)
-        1UL*2*4*6*8*10*12*14*16*18*20*22*24*26*28*30,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18*20*22*24*26*28*30,
         #if (cl_value_len>=59)
-        1UL*3*5*7*9*11*13*15*17*19*21*23*25*27*29*31,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19*21*23*25*27*29*31,
         #if (cl_value_len>=62)
-        1UL*2*4*6*8*10*12*14*16*18*20*22*24*26*28*30*32,
+        UINT64_C(1)*2*4*6*8*10*12*14*16*18*20*22*24*26*28*30*32,
         #if (cl_value_len>=64)
-        1UL*3*5*7*9*11*13*15*17*19*21*23*25*27*29*31*33,
+        UINT64_C(1)*3*5*7*9*11*13*15*17*19*21*23*25*27*29*31*33,
         #if (cl_value_len>=67)
         ...
         #endif
diff --git a/src/integer/misc/combin/cl_I_factorial.cc b/src/integer/misc/combin/cl_I_factorial.cc
index 98b9052..7a8235f 100644
--- a/src/integer/misc/combin/cl_I_factorial.cc
+++ b/src/integer/misc/combin/cl_I_factorial.cc
@@ -32,44 +32,44 @@ const cl_I factorial (uintL n) // assume n >= 0 small
 {
 	static uintV const fakul_table [] = {
         1,
-        1UL,
-        1UL*2,
+        UINT64_C(1),
+        UINT64_C(1)*2,
         #if (cl_value_len>=4)
-        1UL*2*3,
+        UINT64_C(1)*2*3,
         #if (cl_value_len>=6)
-        1UL*2*3*4,
+        UINT64_C(1)*2*3*4,
         #if (cl_value_len>=8)
-        1UL*2*3*4*5,
+        UINT64_C(1)*2*3*4*5,
         #if (cl_value_len>=11)
-        1UL*2*3*4*5*6,
+        UINT64_C(1)*2*3*4*5*6,
         #if (cl_value_len>=14)
-        1UL*2*3*4*5*6*7,
+        UINT64_C(1)*2*3*4*5*6*7,
         #if (cl_value_len>=17)
-        1UL*2*3*4*5*6*7*8,
+        UINT64_C(1)*2*3*4*5*6*7*8,
         #if (cl_value_len>=20)
-        1UL*2*3*4*5*6*7*8*9,
+        UINT64_C(1)*2*3*4*5*6*7*8*9,
         #if (cl_value_len>=23)
-        1UL*2*3*4*5*6*7*8*9*10,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10,
         #if (cl_value_len>=27)
-        1UL*2*3*4*5*6*7*8*9*10*11,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11,
         #if (cl_value_len>=30)
-        1UL*2*3*4*5*6*7*8*9*10*11*12,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12,
         #if (cl_value_len>=34)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13,
         #if (cl_value_len>=38)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13*14,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13*14,
         #if (cl_value_len>=42)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13*14*15,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13*14*15,
         #if (cl_value_len>=46)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16,
         #if (cl_value_len>=50)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17,
         #if (cl_value_len>=54)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18,
         #if (cl_value_len>=58)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19,
         #if (cl_value_len>=63)
-        1UL*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20,
+        UINT64_C(1)*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20,
         #if (cl_value_len>=67)
         ...
         #endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7dfe406..57c0777 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -78,6 +78,7 @@ tests_SOURCES = test.h tests.cc test_I.cc test_I.h test_I_abs.cc test_I_compare.
 	test_I_logcount.cc test_I_ilength.cc test_I_ord2.cc \
 	test_I_power2p.cc test_I_isqrt.cc test_I_sqrtp.cc \
 	test_I_io.cc test_I_GV.cc \
+	test_I_factorial.cc \
 	test_MI.h test_MI.cc test_MI_canonhom.cc test_MI_plus.cc \
 	test_MI_minus.cc test_MI_mul.cc test_MI_recip.cc \
 	test_MI_div.cc test_MI_expt.cc \
diff --git a/tests/test_I.cc b/tests/test_I.cc
index 8e5ea63..5338a31 100644
--- a/tests/test_I.cc
+++ b/tests/test_I.cc
@@ -45,6 +45,8 @@ extern int test_I_sqrtp (int iterations);
 // Miscellaneous.
 extern int test_I_io (int iterations);
 extern int test_I_GV (int iterations);
+extern int test_I_factorial(int iterations);
+extern int test_I_doublefactorial(int iterations);
 
 #define RUN(tester,iterations)  \
 	std::cout << "Testing "#tester"..." << std::endl; \
@@ -99,5 +101,7 @@ int test_I (int iterations)
 	// Miscellaneous.
 	RUN(test_I_io,iterations);
 	RUN(test_I_GV,iterations);
+	RUN(test_I_factorial, iterations);
+	RUN(test_I_doublefactorial, iterations);
 	return error;
 }
diff --git a/tests/test_I_factorial.cc b/tests/test_I_factorial.cc
new file mode 100644
index 0000000..bae2513
--- /dev/null
+++ b/tests/test_I_factorial.cc
@@ -0,0 +1,15 @@
+#include "test_I.h"
+
+int test_I_factorial(int /* iterations */) {
+	int error = 0;
+	cl_I result = factorial(14U);
+	ASSERT1(result > cl_I(UINT64_C(1) << 32), result);
+	return error;
+}
+
+int test_I_doublefactorial(int /* iterations */) {
+	int error = 0;
+	cl_I result = doublefactorial(21U);
+	ASSERT1(result > cl_I(UINT64_C(1) << 32), result);
+	return error;
+}
-- 
2.17.1

