1// This file is part of Eigen, a lightweight C++ template library 2// for linear algebra. 3// 4// Copyright (C) 2015 Benoit Steiner <benoit.steiner.goog@gmail.com> 5// 6// This Source Code Form is subject to the terms of the Mozilla 7// Public License v. 2.0. If a copy of the MPL was not distributed 8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 10#include "main.h" 11 12#include <Eigen/CXX11/Tensor> 13 14 15#if EIGEN_COMP_MSVC 16#define EIGEN_NO_INT128 17#else 18typedef __uint128_t uint128_t; 19#endif 20 21// Only run the test on compilers that support 128bit integers natively 22#ifndef EIGEN_NO_INT128 23 24using Eigen::internal::TensorUInt128; 25using Eigen::internal::static_val; 26 27void VERIFY_EQUAL(TensorUInt128<uint64_t, uint64_t> actual, uint128_t expected) { 28 bool matchl = actual.lower() == static_cast<uint64_t>(expected); 29 bool matchh = actual.upper() == static_cast<uint64_t>(expected >> 64); 30 if (!matchl || !matchh) { 31 const char* testname = g_test_stack.back().c_str(); 32 std::cerr << "Test " << testname << " failed in " << __FILE__ 33 << " (" << __LINE__ << ")" 34 << std::endl; 35 abort(); 36 } 37} 38 39 40void test_add() { 41 uint64_t incr = internal::random<uint64_t>(1, 9999999999); 42 for (uint64_t i1 = 0; i1 < 100; ++i1) { 43 for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) { 44 TensorUInt128<uint64_t, uint64_t> i(i1, i2); 45 uint128_t a = (static_cast<uint128_t>(i1) << 64) + static_cast<uint128_t>(i2); 46 for (uint64_t j1 = 0; j1 < 100; ++j1) { 47 for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) { 48 TensorUInt128<uint64_t, uint64_t> j(j1, j2); 49 uint128_t b = (static_cast<uint128_t>(j1) << 64) + static_cast<uint128_t>(j2); 50 TensorUInt128<uint64_t, uint64_t> actual = i + j; 51 uint128_t expected = a + b; 52 VERIFY_EQUAL(actual, expected); 53 } 54 } 55 } 56 } 57} 58 59void test_sub() { 60 uint64_t incr = internal::random<uint64_t>(1, 9999999999); 61 for (uint64_t i1 = 0; i1 < 100; ++i1) { 62 for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) { 63 TensorUInt128<uint64_t, uint64_t> i(i1, i2); 64 uint128_t a = (static_cast<uint128_t>(i1) << 64) + static_cast<uint128_t>(i2); 65 for (uint64_t j1 = 0; j1 < 100; ++j1) { 66 for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) { 67 TensorUInt128<uint64_t, uint64_t> j(j1, j2); 68 uint128_t b = (static_cast<uint128_t>(j1) << 64) + static_cast<uint128_t>(j2); 69 TensorUInt128<uint64_t, uint64_t> actual = i - j; 70 uint128_t expected = a - b; 71 VERIFY_EQUAL(actual, expected); 72 } 73 } 74 } 75 } 76} 77 78void test_mul() { 79 uint64_t incr = internal::random<uint64_t>(1, 9999999999); 80 for (uint64_t i1 = 0; i1 < 100; ++i1) { 81 for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) { 82 TensorUInt128<uint64_t, uint64_t> i(i1, i2); 83 uint128_t a = (static_cast<uint128_t>(i1) << 64) + static_cast<uint128_t>(i2); 84 for (uint64_t j1 = 0; j1 < 100; ++j1) { 85 for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) { 86 TensorUInt128<uint64_t, uint64_t> j(j1, j2); 87 uint128_t b = (static_cast<uint128_t>(j1) << 64) + static_cast<uint128_t>(j2); 88 TensorUInt128<uint64_t, uint64_t> actual = i * j; 89 uint128_t expected = a * b; 90 VERIFY_EQUAL(actual, expected); 91 } 92 } 93 } 94 } 95} 96 97void test_div() { 98 uint64_t incr = internal::random<uint64_t>(1, 9999999999); 99 for (uint64_t i1 = 0; i1 < 100; ++i1) { 100 for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) { 101 TensorUInt128<uint64_t, uint64_t> i(i1, i2); 102 uint128_t a = (static_cast<uint128_t>(i1) << 64) + static_cast<uint128_t>(i2); 103 for (uint64_t j1 = 0; j1 < 100; ++j1) { 104 for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) { 105 TensorUInt128<uint64_t, uint64_t> j(j1, j2); 106 uint128_t b = (static_cast<uint128_t>(j1) << 64) + static_cast<uint128_t>(j2); 107 TensorUInt128<uint64_t, uint64_t> actual = i / j; 108 uint128_t expected = a / b; 109 VERIFY_EQUAL(actual, expected); 110 } 111 } 112 } 113 } 114} 115 116void test_misc1() { 117 uint64_t incr = internal::random<uint64_t>(1, 9999999999); 118 for (uint64_t i2 = 1; i2 < 100 * incr; i2 += incr) { 119 TensorUInt128<static_val<0>, uint64_t> i(0, i2); 120 uint128_t a = static_cast<uint128_t>(i2); 121 for (uint64_t j2 = 1; j2 < 100 * incr; j2 += incr) { 122 TensorUInt128<static_val<0>, uint64_t> j(0, j2); 123 uint128_t b = static_cast<uint128_t>(j2); 124 uint64_t actual = (i * j).upper(); 125 uint64_t expected = (a * b) >> 64; 126 VERIFY_IS_EQUAL(actual, expected); 127 } 128 } 129} 130 131void test_misc2() { 132 int64_t incr = internal::random<int64_t>(1, 100); 133 for (int64_t log_div = 0; log_div < 63; ++log_div) { 134 for (int64_t divider = 1; divider <= 1000000 * incr; divider += incr) { 135 uint64_t expected = (static_cast<uint128_t>(1) << (64+log_div)) / static_cast<uint128_t>(divider) - (static_cast<uint128_t>(1) << 64) + 1; 136 uint64_t shift = 1ULL << log_div; 137 138 TensorUInt128<uint64_t, uint64_t> result = (TensorUInt128<uint64_t, static_val<0> >(shift, 0) / TensorUInt128<static_val<0>, uint64_t>(divider) - TensorUInt128<static_val<1>, static_val<0> >(1, 0) + TensorUInt128<static_val<0>, static_val<1> >(1)); 139 uint64_t actual = static_cast<uint64_t>(result); 140 VERIFY_IS_EQUAL(actual, expected); 141 } 142 } 143} 144#endif 145 146 147void test_cxx11_tensor_uint128() 148{ 149#ifdef EIGEN_NO_INT128 150 // Skip the test on compilers that don't support 128bit integers natively 151 return; 152#else 153 CALL_SUBTEST_1(test_add()); 154 CALL_SUBTEST_2(test_sub()); 155 CALL_SUBTEST_3(test_mul()); 156 CALL_SUBTEST_4(test_div()); 157 CALL_SUBTEST_5(test_misc1()); 158 CALL_SUBTEST_6(test_misc2()); 159#endif 160} 161