Skip to content

Commit

Permalink
adding a two-parameter skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
Ravenwater committed Feb 23, 2024
1 parent b3a3c2d commit 80a8e49
Show file tree
Hide file tree
Showing 9 changed files with 758 additions and 0 deletions.
40 changes: 40 additions & 0 deletions include/universal/number/skeleton_2params/attributes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once
// attributes.hpp: information functions for two-parameter number and value attributes
//
// Copyright (C) 2017 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
#include <cmath> // for std:pow()

namespace sw { namespace universal {

// functions to provide details about
// the properties of the number system configuration
// in terms of native types.
// Since many number system configurations cannot be represented by
// native types, these are all convenience functions.
// They should not be used for the core algorithms.

// free function sign
template<unsigned nbits, unsigned es, typename bt>
bool sign(const twoparam<nbits, bt>& v) {
return v.sign();
}

// generate the maxneg through maxpos value range of a logarithmic number system configuration
// the type of arithmetic, Modulo or Saturating, does not affect the range
template<unsigned nbits, unsigned es, typename bt>
std::string twoparam_range(const twoparam<nbits, bt) {
using TWOPARAM = twoparam<nbits, bt>;
std::stringstream s;
TWOPARAM l;
s << std::setw(45) << type_tag(v) << " : [ "
<< l.maxneg() << " ... "
<< l.minneg() << " "
<< "0 "
<< l.minpos() << " ... "
<< l.maxpos() << " ]";
return s.str();
}

}} // namespace sw::universal
74 changes: 74 additions & 0 deletions include/universal/number/skeleton_2params/bla
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once
// exceptions.hpp: exception hierarchy for exceptions during posit calculations
//
// Copyright (C) 2017 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
#include <universal/common/exceptions.hpp>

namespace sw { namespace universal {

///////////////////////////////////////////////////////////////////////////////////////////////////
/// POSIT ARITHMETIC EXCEPTIONS

// base class for posit arithmetic exceptions
struct posit_arithmetic_exception : public universal_arithmetic_exception {
posit_arithmetic_exception(const std::string& error)
: universal_arithmetic_exception(std::string("posit arithmetic exception: ") + error) {};
};

//////////////////////////////////////////////////////////////////////////////////////////////////
/// specialized exceptions to aid application level exception handling

// not_a_real is thrown when a rvar is NaR
struct posit_nar : public posit_arithmetic_exception {
posit_nar() : posit_arithmetic_exception("nar (not a real)") {}
};

// divide_by_zero is thrown when the denominator in a division operator is 0
struct posit_divide_by_zero : public posit_arithmetic_exception {
posit_divide_by_zero() : posit_arithmetic_exception("divide by zero") {}
};

// divide_by_nar is thrown when the denominator in a division operator is NaR
struct posit_divide_by_nar : public posit_arithmetic_exception {
posit_divide_by_nar() : posit_arithmetic_exception("divide by nar") {}
};

// numerator_is_nar is thrown when the numerator in a division operator is NaR
struct posit_numerator_is_nar : public posit_arithmetic_exception {
posit_numerator_is_nar() : posit_arithmetic_exception("numerator is nar") {}
};

// operand_is_nar is thrown when an rvar in a binary operator is NaR
struct posit_operand_is_nar : public posit_arithmetic_exception {
posit_operand_is_nar() : posit_arithmetic_exception("operand is nar") {}
};

// thrown when division yields no signficant fraction bits
struct posit_division_result_is_zero : public posit_arithmetic_exception {
posit_division_result_is_zero() : posit_arithmetic_exception("division yielded no significant bits") {}
};

// thrown when division yields NaR
struct posit_division_result_is_infinite : public posit_arithmetic_exception {
posit_division_result_is_infinite() : posit_arithmetic_exception("division yielded infinite") {}
};

///////////////////////////////////////////////////////////////////////////////////////////////////
/// POSIT INTERNAL OPERATION EXCEPTIONS

struct posit_internal_exception : public universal_internal_exception {
posit_internal_exception(const std::string& error)
: universal_internal_exception(std::string("posit internal exception: ") + error) {};
};

struct posit_hpos_too_large : public posit_internal_exception {
posit_hpos_too_large() : posit_internal_exception("position of hidden bit too large for given posit") {}
};

struct posit_rbits_too_large : public posit_internal_exception {
posit_rbits_too_large() :posit_internal_exception("number of remaining bits too large for this fraction") {}
};

}} // namespace sw::universal
75 changes: 75 additions & 0 deletions include/universal/number/skeleton_2params/exceptions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#pragma once
// exceptions.hpp: exception hierarchy for exceptions during arithmetic calculations
//
// Copyright (C) 2017 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
#include <universal/common/exceptions.hpp>

namespace sw { namespace universal {

///////////////////////////////////////////////////////////////////////////////////////////////////
/// BASE ARITHMETIC EXCEPTIONS

// base class for twoparam arithmetic exceptions
struct twoparam_arithmetic_exception : public universal_arithmetic_exception {
twoparam_arithmetic_exception(const std::string& error)
: universal_arithmetic_exception(std::string("twoparam arithmetic exception: ") + error) {};
};

//////////////////////////////////////////////////////////////////////////////////////////////////
/// specialized exceptions to aid application level exception handling

// not_a_real is thrown when a rvar is NaR
struct twoparam_nar : public twoparam_arithmetic_exception {
twoparam_nar() : twoparam_arithmetic_exception("nar (not a real)") {}
};

// divide_by_zero is thrown when the denominator in a division operator is 0
struct twoparam_divide_by_zero : public twoparam_arithmetic_exception {
twoparam_divide_by_zero() : twoparam_arithmetic_exception("divide by zero") {}
};

// divide_by_nar is thrown when the denominator in a division operator is NaR
struct twoparam_divide_by_nar : public twoparam_arithmetic_exception {
twoparam_divide_by_nar() : twoparam_arithmetic_exception("divide by nar") {}
};

// numerator_is_nar is thrown when the numerator in a division operator is NaR
struct twoparam_numerator_is_nar : public twoparam_arithmetic_exception {
twoparam_numerator_is_nar() : twoparam_arithmetic_exception("numerator is nar") {}
};

// operand_is_nar is thrown when an rvar in a binary operator is NaR
struct twoparam_operand_is_nar : public twoparam_arithmetic_exception {
twoparam_operand_is_nar() : twoparam_arithmetic_exception("operand is nar") {}
};

// thrown when division yields no signficant fraction bits
struct twoparam_division_result_is_zero : public twoparam_arithmetic_exception {
twoparam_division_result_is_zero() : twoparam_arithmetic_exception("division yielded no significant bits") {}
};

// thrown when division yields NaR
struct twoparam_division_result_is_nar : public twoparam_arithmetic_exception {
twoparam_division_result_is_nar() : twoparam_arithmetic_exception("division yielded nar") {}
};

///////////////////////////////////////////////////////////////////////////////////////////////////
/// INTERNAL OPERATION EXCEPTIONS

struct twoparam_internal_exception : public universal_internal_exception {
twoparam_internal_exception(const std::string& error)
: universal_internal_exception(std::string("twoparam internal exception: ") + error) {};
};

struct twoparam_hpos_too_large : public twoparam_internal_exception {
twoparam_hpos_too_large() : twoparam_internal_exception("twoparamion of hidden bit too large for given twoparam") {}
};

struct twoparam_rbits_too_large : public twoparam_internal_exception {
twoparam_rbits_too_large() :twoparam_internal_exception("number of remaining bits too large for this fraction") {}
};


}} // namespace sw::universal
87 changes: 87 additions & 0 deletions include/universal/number/skeleton_2params/manipulators.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#pragma once
// manipulators.hpp: definitions of helper functions for twoparam numbers manipulation
//
// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.
#include <iostream>
#include <iomanip>
#include <typeinfo> // for typeid()

// pull in the color printing for shells utility
#include <universal/utility/color_print.hpp>

namespace sw { namespace universal {

// Generate a type tag for this twoparam
template<typename TwoParamType,
std::enable_if_t< is_twoparam<TwoParamType>, bool> = true
>
inline std::string type_tag(const TwoParamType & = {}) {
std::stringstream s;
typename TwoParamType::BlockType bt{0};
s << "twoparam<"
<< std::setw(3) << TwoParamType::nbits << ", "
<< std::setw(3) << TwoParamType::es << ", "
<< type_tag(bt) << ", "
<< std::setw(10) << type_tag(Behavior{ TwoParamType::behavior }) << '>';
return s.str();
}

template<typename TwoParamType,
std::enable_if_t< is_twoparam<TwoParamType>, bool> = true
>
inline std::string range(const TwoParamType & = {}) {
std::stringstream s;
TwoParamType b(SpecificValue::maxneg), c(SpecificValue::minneg), d(SpecificValue::minpos), e(SpecificValue::maxpos);
s << "[" << b << " ... " << c << ", 0, " << d << " ... " << e << "]\n";
return s.str();
}

// report if a native floating-point value is within the dynamic range of the twoparam configuration
template<typename TwoParamType,
std::enable_if_t< is_twoparam<TwoParamType>, bool> = true
>
inline bool isInRange(double v) {
TwoParamType a{};

bool inside = true;
if (v > double(a.maxpos()) || v < double(a.maxneg())) inside = false;
return inside;
}

template<typename TwoParamType,
std::enable_if_t< is_twoparam<TwoParamType>, bool> = true
>
inline std::string color_print(const TwoParamType& l, bool nibbleMarker = false) {

std::stringstream s;

Color red(ColorCode::FG_RED);
Color yellow(ColorCode::FG_YELLOW);
Color blue(ColorCode::FG_BLUE);
Color magenta(ColorCode::FG_MAGENTA);
Color cyan(ColorCode::FG_CYAN);
Color white(ColorCode::FG_WHITE);
Color def(ColorCode::FG_DEFAULT);
s << red << (l.sign() ? "1" : "0");

// integer bits
for (int i = static_cast<int>(TwoParamType::nbits) - 2; i >= static_cast<int>(TwoParamType::rbits); --i) {
s << cyan << (l.at(static_cast<unsigned>(i)) ? '1' : '0');
if ((i - TwoParamType::rbits) > 0 && ((i - TwoParamType::rbits) % 4) == 0 && nibbleMarker) s << yellow << '\'';
}

// fraction bits
if constexpr (TwoParamType::rbits > 0) {
s << magenta << '.';
for (int i = static_cast<int>(TwoParamType::rbits) - 1; i >= 0; --i) {
s << magenta << (l.at(static_cast<unsigned>(i)) ? '1' : '0');
if (i > 0 && (i % 4) == 0 && nibbleMarker) s << yellow << '\'';
}
}
s << def;
return s.str();
}

}} // namespace sw::universal
72 changes: 72 additions & 0 deletions include/universal/number/skeleton_2params/mathlib.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#pragma once
// mathlib.hpp: elementary functions for the twoparam number system
//
// Copyright (C) 2017 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

/*
https://en.wikipedia.org/wiki/Elementary_function
In mathematics, an elementary function is a function of one variable which is a finite sum,
product, and/or comtwoparamion of the rational functions (P(x)/Q(x) for polynomials P and Q),
sin, cos, exp, and their inverse functions (including arcsin, log, x^(1/n)).
Elementary functions were introduced by Joseph Liouville in a series of papers from 1833 to 1841.
An algebraic treatment of elementary functions was started by Joseph Fels Ritt in the 1930s.
*/
#include <universal/number/twoparam/math/classify.hpp>
#include <universal/number/twoparam/math/complex.hpp>
#include <universal/number/twoparam/math/error_and_gamma.hpp>
#include <universal/number/twoparam/math/exponent.hpp>
#include <universal/number/twoparam/math/fractional.hpp>
#include <universal/number/twoparam/math/hyperbolic.hpp>
#include <universal/number/twoparam/math/hypot.hpp>
#include <universal/number/twoparam/math/logarithm.hpp>
#include <universal/number/twoparam/math/minmax.hpp>
#include <universal/number/twoparam/math/next.hpp>
#include <universal/number/twoparam/math/pow.hpp>
#include <universal/number/twoparam/math/sqrt.hpp>
#include <universal/number/twoparam/math/trigonometry.hpp>
#include <universal/number/twoparam/math/truncate.hpp>

namespace sw { namespace universal {
//////////////////////////////////////////////////////////////////////////

// calculate the integer power a ^ b
// exponentiation by squaring is the standard method for modular exponentiation of large numbers in asymmetric cryptography
template<unsigned nbits, unsigned es, typename BlockType>
twoparam<nbits, es, BlockType> ipow(const twoparam<nbits, es, BlockType>& a, const twoparam<nbits, es, BlockType>& b) {
// precondition
if (!a.isinteger() || !b.isinteger()) return twoparam<nbits, es, BlockType>(0);

// TODO: using uint64_t as ipow constraints dynamic range
uint64_t result(1);
uint64_t base = uint64_t(a);
uint64_t exp = uint64_t(b);
for (;;) {
if (exp & 0x1) result *= base;
exp >>= 1;
if (exp == 0) break;
base *= base;
}
return twoparam<nbits, BlockType>(result);
}

// clang <complex> implementation is calling these functions so we need implementations for twoparam

// already defined in math/classify.hpp
//template<unsigned nbits, unsigned es>
//inline bool isnan(const twoparam<nbits, es>& p) { return p.isnar(); }
//
//template<unsigned nbits, unsigned es>
//inline bool isinf(const twoparam<nbits, es>& p) { return p.isnar(); }

// copysign returns a value with the magnitude of a, and the sign of b
template<unsigned nbits, unsigned es, typename BlockType>
inline twoparam<nbits, es, BlockType> copysign(const twoparam<nbits, es, BlockType>& a, const twoparam<nbits, es, BlockType>& b) {
twoparam<nbits, es, BlockType> c(a);
if (a.sign() == b.sign()) return c;
return -c;
}
}}
Loading

0 comments on commit 80a8e49

Please sign in to comment.