-
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adding a posit oracle as a separate data type to be used to validate …
…specialized posits
- Loading branch information
1 parent
cac65dc
commit 025e51f
Showing
18 changed files
with
3,645 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
======================================================================== | ||
Posit Project Overview | ||
======================================================================== | ||
|
||
Random 32 bits which is intentionally zero heavy | ||
----------------- | ||
Sign | ||
| | ||
| | ||
v | ||
1100 1000 1100 0100 0100 0010 0001 0001 | ||
|
||
How to decode this? | ||
|
||
Here is some pseudocode that should work on any bit sequence. Suppose | ||
|
||
n is the number of bits (which in the example is 32), | ||
es is the number of exponent bits (es = 3 in the example since n = 32), | ||
p is the bit sequence treated as a signed integer. | ||
|
||
Also suppose, though it is not the convention, that the bits are numbered from left to right starting with 1, | ||
so the sign bit is bit 1 and the rightmost (least significant) bit is bit n. That numbering makes the pseudocode | ||
more readable. Assume we have a quick machine instruction FindFirstOne(p) that finds the position of the first 1 bit | ||
in p, returning n+1 if all bits are zero, and a similar instruction FindFirstZero(p). The function Bits(j..k, p) | ||
extracts bits j through k of p, clipped to bit n. If j is greater than n, Bits(j..k, p) returns zero. | ||
|
||
We seek x, the value represented by p. The green text indicates what would happen for the 32 bits in the example. | ||
|
||
(* Check for exception values: *) | ||
If Bits(2..n, p) == 0, (* Check for a string of all zeros after the first bit. *) | ||
If Bits(1..1, p) == 0, (* If the first bit is also zero, then x is zero. *) | ||
x ← 0; | ||
Else, (* The first bit must be one, indicating x is unsigned infinity. *) | ||
x ← ±∞; | ||
End If; | ||
End; (* Can cut out early. *) | ||
End If; | ||
|
||
The example sequence fails the exception value tests, so continue. | ||
|
||
(* Process sign bit: *) | ||
If Bits(1..1, p) == 1, sign ← –1; p ← –p; (* 2's complement negate p. *) | ||
Else sign ← 1; | ||
End If; | ||
|
||
The first bit is a 1, so sign = -1 and p gets negated. Flip all the bits and add 1: | ||
0011 0111 0011 1011 1011 1101 1110 1111 | ||
|
||
(* Process regime bits. The second bit, r, determines the sign of the regime. *) | ||
r ← Bits(2..2, p) | ||
Bits(1..1, p) ← r (* Duplicate first regime bit into sign bit so the "FindFirst..." instructions work. *) | ||
If r == 0, (* regime value is negative *) | ||
k = FindFirstOne(p); | ||
shift ← –(2^es) × (k – 2); (* Actually a shift of k-2 by a shift by es, so this is fast. *) | ||
Else (* regime value is zero or positive *) | ||
k = FindFirstZero(p); | ||
shift ← (2^es) × (k – 3); | ||
End If; | ||
|
||
The example 001... has r = 0 so the regime value is negative. The first 1 occurs in bit 3, | ||
so the regime represents –1 and contributes a shift of –(2^es) = –8. This leaves k pointing to bit 3. | ||
The exponent will be in the next es bits after bit 3, which will fine-tune the shift roughed out by the regime bits. | ||
|
||
(* Add the exponent bits, as an unsigned integer, to the shift. *) | ||
shift ← shift + Bits(k+1..k+es, p); | ||
|
||
The three exponent bits in the example are the underlined ones: 0011 0111 0011 1011 1011 1101 1110 1111. | ||
As an unsigned binary integer, 101 means decimal 5, so the shift is –8 + 5 = –3. | ||
|
||
(* The remaining bits are the fraction, with a hidden bit of 1, so we're done. It looks like a regular float: *) | ||
x ← sign × 2^shift × 1.Bits(k+es+1..n) | ||
End | ||
|
||
The fraction bits in the example are underlined: 0011 0111 0011 1011 1011 1101 1110 1111. That fraction, | ||
plus the hidden bit 1, is 121355759/(2^26), or exactly 1.80834172666072845458984375. | ||
Scale this by 2^(shift) = 2^(–3) = 1/8, and the sign, to get –0.22604271583259105682373046875. | ||
Notice that there are three more bits in the fraction than there are in an IEEE 32-bit float, | ||
giving almost a full decimal more accuracy. | ||
|
||
I didn't actually run the above pseudocode so it may contain a typo or two, but it is closely based on the | ||
Mathematica code for decoding a posit and that has been debugged and in use for months. | ||
It is possible to decode the bit string _without_ doing 2's complement negation if the sign bit is zero | ||
(the hidden bit for negative posits represents –2, not 1!), which according to Isaac Yonemoto leads to | ||
simpler hardware... but it creates a more cryptic pseudocode explanation, so I used the 2's complement negation here. | ||
|
||
///////////////////////////////////////////////////////////////////////////// |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
// attributes.hpp: functions to query number system 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. | ||
|
||
namespace sw { namespace universal { | ||
|
||
// functions to provide details about properties of a posit configuration | ||
|
||
using namespace sw::universal::internal; | ||
|
||
// calculate the scale of a posit | ||
template<unsigned nbits, unsigned es> | ||
inline int scale(const posito<nbits, es>& p) { | ||
regime<nbits, es> _regime; | ||
exponent<nbits, es> _exponent; | ||
internal::bitblock<nbits> tmp(p.get()); | ||
tmp = sign(p) ? internal::twos_complement(tmp) : tmp; | ||
int k = decode_regime(tmp); | ||
unsigned nrRegimeBits = _regime.assign_regime_pattern(k); // get the regime bits | ||
_exponent.extract_exponent_bits(tmp, nrRegimeBits); // get the exponent bits | ||
// return the scale | ||
return _regime.scale() + _exponent.scale(); | ||
} | ||
|
||
}} // namespace sw::universal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 posito_arithmetic_exception : public universal_arithmetic_exception { | ||
posito_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 posito_nar : public posito_arithmetic_exception { | ||
posito_nar() : posito_arithmetic_exception("nar (not a real)") {} | ||
}; | ||
|
||
// divide_by_zero is thrown when the denominator in a division operator is 0 | ||
struct posito_divide_by_zero : public posito_arithmetic_exception { | ||
posito_divide_by_zero() : posito_arithmetic_exception("divide by zero") {} | ||
}; | ||
|
||
// divide_by_nar is thrown when the denominator in a division operator is NaR | ||
struct posito_divide_by_nar : public posito_arithmetic_exception { | ||
posito_divide_by_nar() : posito_arithmetic_exception("divide by nar") {} | ||
}; | ||
|
||
// numerator_is_nar is thrown when the numerator in a division operator is NaR | ||
struct posito_numerator_is_nar : public posito_arithmetic_exception { | ||
posito_numerator_is_nar() : posito_arithmetic_exception("numerator is nar") {} | ||
}; | ||
|
||
// operand_is_nar is thrown when an rvar in a binary operator is NaR | ||
struct posito_operand_is_nar : public posito_arithmetic_exception { | ||
posito_operand_is_nar() : posito_arithmetic_exception("operand is nar") {} | ||
}; | ||
|
||
// thrown when division yields no signficant fraction bits | ||
struct posito_division_result_is_zero : public posito_arithmetic_exception { | ||
posito_division_result_is_zero() : posito_arithmetic_exception("division yielded no significant bits") {} | ||
}; | ||
|
||
// thrown when division yields NaR | ||
struct posito_division_result_is_infinite : public posito_arithmetic_exception { | ||
posito_division_result_is_infinite() : posito_arithmetic_exception("division yielded infinite") {} | ||
}; | ||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////// | ||
/// POSIT INTERNAL OPERATION EXCEPTIONS | ||
|
||
struct posito_internal_exception : public universal_internal_exception { | ||
posito_internal_exception(const std::string& error) | ||
: universal_internal_exception(std::string("posit internal exception: ") + error) {}; | ||
}; | ||
|
||
struct posito_hpos_too_large : public posito_internal_exception { | ||
posito_hpos_too_large() : posito_internal_exception("position of hidden bit too large for given posit") {} | ||
}; | ||
|
||
struct posito_rbits_too_large : public posito_internal_exception { | ||
posito_rbits_too_large() :posito_internal_exception("number of remaining bits too large for this fraction") {} | ||
}; | ||
|
||
}} // namespace sw::universal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
#pragma once | ||
// fdp.hpp : include file containing templated C++ interfaces to fused dot product | ||
// | ||
// 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 <iostream> | ||
#include <vector> | ||
#include <universal/traits/posito_traits.hpp> | ||
|
||
namespace sw { namespace universal { | ||
|
||
/// ////////////////////////////////////////////////////////////////// | ||
/// fused dot product operators | ||
/// fdp_qc fused dot product with quire continuation | ||
/// fdp_stride fused dot product with non-negative stride | ||
/// fdp fused dot product of two vectors | ||
|
||
// Fused dot product with quire continuation | ||
template<typename Qy, typename Vector> | ||
void fdp_qc(Qy& sum_of_products, size_t n, const Vector& x, size_t incx, const Vector& y, size_t incy) { | ||
size_t ix, iy; | ||
for (ix = 0, iy = 0; ix < n && iy < n; ix = ix + incx, iy = iy + incy) { | ||
sum_of_products += sw::universal::quire_mul(x[ix], y[iy]); | ||
} | ||
} | ||
|
||
// Resolved fused dot product, with the option to control capacity bits in the quire | ||
template<typename Vector> | ||
enable_if_posito<value_type<Vector>, value_type<Vector> > // as return type | ||
fdp_stride(size_t n, const Vector& x, size_t incx, const Vector& y, size_t incy) { | ||
constexpr unsigned nbits = Vector::value_type::nbits; | ||
constexpr unsigned es = Vector::value_type::es; | ||
constexpr unsigned capacity = 20; // support vectors up to 1M elements | ||
quire<nbits, es, capacity> q = 0; | ||
size_t ix, iy; | ||
for (ix = 0, iy = 0; ix < n && iy < n; ix = ix + incx, iy = iy + incy) { | ||
q += sw::universal::quire_mul(x[ix], y[iy]); | ||
if (sw::universal::_trace_quire_add) std::cout << q << '\n'; | ||
} | ||
typename Vector::value_type sum; | ||
convert(q.to_value(), sum); // one and only rounding step of the fused-dot product | ||
return sum; | ||
} | ||
|
||
#if defined(_MSC_VER) | ||
/* Microsoft Visual Studio. --------------------------------- */ | ||
// Specialized resolved fused dot product that assumes unit stride and a standard vector | ||
template<typename Vector> | ||
enable_if_posito<value_type<Vector>, value_type<Vector> > // as return type | ||
fdp(const Vector& x, const Vector& y) { | ||
constexpr unsigned nbits = Vector::value_type::nbits; | ||
constexpr unsigned es = Vector::value_type::es; | ||
constexpr unsigned capacity = 20; // support vectors up to 1M elements | ||
quire<nbits, es, capacity> q(0); | ||
size_t ix, iy, n = size(x); | ||
for (ix = 0, iy = 0; ix < n && iy < n; ++ix, ++iy) { | ||
q += sw::universal::quire_mul(x[ix], y[iy]); | ||
} | ||
typename Vector::value_type sum; | ||
convert(q.to_value(), sum); // one and only rounding step of the fused-dot product | ||
return sum; | ||
} | ||
#else | ||
|
||
// template<typename Scalar> constexpr auto size(const std::vector<Scalar>& v) -> decltype(v.size()) { return (v.size()); } | ||
|
||
// Specialized resolved fused dot product that assumes unit stride and a standard vector | ||
template<typename Vector> | ||
enable_if_posito<value_type<Vector>, value_type<Vector> > // as return type | ||
fdp(const Vector& x, const Vector& y) { | ||
constexpr unsigned nbits = Vector::value_type::nbits; | ||
constexpr unsigned es = Vector::value_type::es; | ||
constexpr unsigned capacity = 20; // support vectors up to 1M elements | ||
quire<nbits, es, capacity> q(0); | ||
size_t ix, iy, n = size(x); | ||
for (ix = 0, iy = 0; ix < n && iy < n; ++ix, ++iy) { | ||
q += sw::universal::quire_mul(x[ix], y[iy]); | ||
} | ||
typename Vector::value_type sum; | ||
convert(q.to_value(), sum); // one and only rounding step of the fused-dot product | ||
return sum; | ||
} | ||
#endif | ||
|
||
}} // namespace sw::universal | ||
|
Oops, something went wrong.