From 3ea48e8ebe25686f2342cd79b32409fcd1bccb28 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Fri, 15 Feb 2019 19:26:41 -0400
Subject: [PATCH] Implement 128 bits Unsigned Integer Multiplication and
 Division.

---
 src/common/CMakeLists.txt |  2 ++
 src/common/uint128.cpp    | 18 ++++++++++++++++++
 src/common/uint128.h      | 30 ++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+)
 create mode 100644 src/common/uint128.cpp
 create mode 100644 src/common/uint128.h

diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index bdd885273c..b0174b445e 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -113,6 +113,8 @@ add_library(common STATIC
     threadsafe_queue.h
     timer.cpp
     timer.h
+    uint128.cpp
+    uint128.h
     vector_math.h
     web_result.h
 )
diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp
new file mode 100644
index 0000000000..aea7f03e21
--- /dev/null
+++ b/src/common/uint128.cpp
@@ -0,0 +1,18 @@
+
+namespace Common {
+
+std::pair<u64, u64> udiv128(u128 dividend, u64 divisor) {
+    u64 remainder = dividend[0] % divisor;
+    u64 accum = dividend[0] / divisor;
+    if (dividend[1] == 0)
+        return {accum, remainder};
+    // We ignore dividend[1] / divisor as that overflows
+    u64 first_segment = (dividend[1] % divisor) << 32;
+    accum += (first_segment / divisor) << 32;
+    u64 second_segment = (first_segment % divisor) << 32;
+    accum += (second_segment / divisor);
+    remainder += second_segment % divisor;
+    return {accum, remainder};
+}
+
+} // namespace Common
diff --git a/src/common/uint128.h b/src/common/uint128.h
new file mode 100644
index 0000000000..fda313bccc
--- /dev/null
+++ b/src/common/uint128.h
@@ -0,0 +1,30 @@
+#include <array>
+#include <cstdint>
+#include <utility>
+#include <cstring>
+#include "common/common_types.h"
+
+namespace Common {
+
+#ifdef _MSC_VER
+#include <intrin.h>
+
+#pragma intrinsic(_umul128)
+#endif
+
+inline u128 umul128(u64 a, u64 b) {
+#ifdef _MSC_VER
+u128 result;
+result[0] = _umul128(a, b, &result[1]);
+#else
+unsigned __int128 tmp = a;
+tmp *= b;
+u128 result;
+std::memcpy(&result, &tmp, sizeof(u128));
+#endif
+return result;
+}
+
+std::pair<u64, u64> udiv128(u128 dividend, u64 divisor);
+
+} // namespace Common
-- 
GitLab