Examples
In the examples folder you can find some ready-to-try examples that deepen on some of the functionalities of the cppposit library and possible integration with other libraries.
You can compile all the examples as follows:
cmake -B builddir
cmake --build builddir --target examples
You will find the executables as follows:
➜ cppposit git:(main) ✗ tree -L 1 builddir/examples
builddir/examples
├── example_01_basic
├── example_02_deepinit
├── example_03_stl
├── example_04_eigen
├── example_05_fft
├── example_05_tabulatedposit
├── example_06_logging
├── example_06_pseudosig
├── example_07_pseudotanh
├── example_08_fused
├── example_98_backendhw
└── example_99_debugger
Table of Contents
- Basic
- Deep Initialization
- STL
- Eigen
- FFT
- Logging
- Pseudo Sigmoid
- Pseudo Tanh
- Fused Operations
- HW Backend
Basic
#include <iostream>
#include <vector>
using namespace std;
using namespace posit;
#include <posit.h> // include non-tabulated posits
int main() {
Posit<int32_t, 32, 2, uint32_t, PositSpec::WithInfs> One(1);
Posit<int32_t, 32, 2, uint32_t, PositSpec::WithInfs> Tiny(0.00000000000000003);
auto Min = Posit<int32_t, 32, 2, uint32_t, PositSpec::WithInfs>::from_sraw(1);
auto ot = One - Tiny;
auto eps = One - One.prev();
printf("One val:\t %.23f\n", (double)One);
printf("Tiny val:\t %.23f\n", (double)Tiny);
printf("Epsilon:\t %.23f\n", (double)eps);
printf("Min:\t %.64f\n", (double)Min);
printf("One - tiny:\t %.23f\n", (double)(ot));
printf("One - eps:\t %.23f\n", (double)(One - eps));
printf("One previous:\t %.23f\n", (double)One.prev());
std::cout << eps.v << " " << Tiny.v << std::endl;
}
Deep initialization
#include <iostream>
#include <vector>
using namespace std;
#include <posit.h>
using namespace posit;
int main() {
cout << "This demo shows the use of deep initialization of a posit" << endl;
cout << "and the PositTrait class" << endl;
using real = Posit<int8_t, 8, 0, uint16_t, PositSpec::WithNan>;
using PT = PositTrait<int8_t,8,0,PositSpec::WithNan>;
// Let us create a posit, initialized to zero (POSIT_ZERO is not defined, being it equal to 0)
real a(real::DeepInit(), 0);
cout << dec << a << " -> " << oct << a << endl;
// Let us create another posit, initialized to 1
real b(real::DeepInit(), PT::POSIT_ONE);
cout << dec << b << " -> " << oct << b << endl;
// Let us create another posit, initialized to two
real c(real::DeepInit(), PT::POSIT_TWO);
cout << dec << c << " -> " << oct << c << endl;
// Let us create another posit, initialized to MAXPOS
real d(real::DeepInit(), PT::POSIT_MAXPOS);
cout << dec << d << " -> " << oct << d << endl;
// Let us create another posit, initialized to -1
real e(real::DeepInit(), PT::POSIT_MONE);
cout << dec << e << " -> " << oct << e << endl;
// Loop for printing all the positive posits
real counter(real::DeepInit(), 0); //
for (int i = 0; i < 128; i++){
cout << dec << i+1 << ": " << counter << " -> " << oct << counter << endl;
counter = counter.next();
}
return 0;
}
Standard Template Library
#include <iostream>
#include <vector>
using namespace std;
#include "../../include/posit.h" // include non-tabulated posits
using namespace posit;
int main() {
//using real = Posit<int8_t, 8, 3, uint16_t, PositSpec::WithNan>;
// using real = Posit<int16_t, 16, 1, uint32_t, PositSpec::WithNan>;
using real = Posit<int32_t, 32, 2, uint64_t, PositSpec::WithNan>;
// Let us define a vector of posits of length DIM
const int DIM = 5;
vector <real> v(DIM);
v[0] = int(1);
v[1] = int(2);
v[2] = 0.52f;
v[3] = 0.53f;
v[4] = 0.50003f;
// Let us print it on screen
cout << endl<< endl << "Vector v: " << endl;
cout << endl << "[ ";
for (int i = 0; i < DIM; i++)
cout << v[i] <<' ';
cout << "]" << endl;
// Let us define a rectangular matrix of size DIM x (DIM-1)
vector<vector<real>> M(DIM, std::vector<real>(DIM - 1));
// Let us define a rectangular matrix of size DIM x (DIM-1)
cout << endl<< endl << "Matrix M: " << endl;
for(int i = 0; i < DIM; i++){
for (int j = 0; j < DIM - 1; j++) {
M[i][j] = (i + j) + 0.2;
cout << float(M[i][j]) << ' ';
}
cout << endl;
}
return 0;
}
Eigen Library
#include<iostream>
#include "../../include/posit.h"
#include<cstdlib>
#include<Eigen/Dense>
using namespace std;
int main() {
// Step1. Create a 3-by-3 random matrix, filled with posits
using myFloat = posit::Posit<int32_t, 32, 0, uint32_t, posit::PositSpec::WithNan>;
Eigen::Matrix<myFloat,3,3> m;
for(int i = 0; i < 3; ++i) {
for(int j = 0; j < 3; ++j) {
m(i,j) = myFloat((double(rand()%200))/100);
std::cout << m(i,j) << " " ;
}
std::cout << std::endl;
}
std::cout << std::endl;
// Step2. compute its inverse
Eigen::Matrix<myFloat,3,3> minv = m.inverse();
// Step3. print it on screen
for(int i = 0; i < 3; ++i) {
for(int j = 0; j < 3; ++j) {
std::cout << minv(i,j) << " " ;
}
std::cout << std::endl;
}
std::cout << std::endl;
// Step4. check wether the product of the original matrix and its inverse gives the identity matrix
Eigen::Matrix<myFloat,3,3> prod = m*minv;
for(int i = 0; i < 3; ++i) {
for(int j = 0; j < 3; ++j) {
std::cout << prod(i,j) << " " ;
}
std::cout << std::endl;
}
return 0;
}
Fast Fourier Transform
#include <iostream>
#include "posit.h"
typedef posit::Posit<int32_t,32,2,uint32_t,posit::PositSpec::WithNan> real;
constexpr unsigned int k = 8; /* for 2^8 = 256 points */
constexpr unsigned N = (1 << k); /* N-point FFT */
typedef struct{
real Re;
real Im;
}
complex;
#ifndef PI
#define PI real(3.14159265358979323846264338327950288)
#endif
void fft(complex * signal, const unsigned int n, complex * tmp) {
if (n > 1) {
/* return if n =< 0 */
unsigned int k, m;
complex z, w, *vo, *ve;
ve = tmp;
vo = tmp + n / 2;
for (k = 0; k < n / 2; k++) {
ve[k] = signal[2 * k];
vo[k] = signal[2 * k + 1];
}
fft(ve, n / 2, signal); // FFT on even-indexed elements of signal[]
fft(vo, n / 2, signal); // FFT on odd-indexed elements of signal[]
for (m = 0; m < n / 2; m++) {
w.Re = (std::cos((real(2) * PI * real(m) / real(n))));
w.Im = -(std::sin((real(2) * PI * real(m) / real(n))));
z.Re = w.Re * vo[m].Re - w.Im * vo[m].Im; /* Re(w*vo[m]) */
z.Im = w.Re * vo[m].Im + w.Im * vo[m].Re; /* Im(w*vo[m]) */
signal[m].Re = ve[m].Re + z.Re;
signal[m].Im = ve[m].Im + z.Im;
signal[m + n / 2].Re = ve[m].Re - z.Re;
signal[m + n / 2].Im = ve[m].Im - z.Im;
}
}
return;
}
// Program entry point.
int main() {
complex signal[N], tmp[N];
unsigned int k;
/* Fill signal[] as the sum of two pure sine signals of known frequency */
for (k = 0; k < N; k++) {
signal[k].Re = real(0.125) * std::cos((real(2) * PI * real(k) / real(N))) + real(0.5) * std::cos((real(2) * PI * real(10*k) / real(N)));
signal[k].Im = real(0.125) * std::sin((real(2) * PI * real(k) / real(N))) + real(0.5) * std::cos((real(2) * PI * real(10*k) / real(N)));
}
/* Printing the generated signal (for reading it in Matlab)*/
std::cout << "signal = [\n";
for (k = 0; k < N; k++) {
std::cout << signal[k].Re << "+" << signal[k].Im <<"i" << std::endl;
}
std::cout << "]; \n\n";
std::cout << "Computing the FFT...\n";
fft(signal, N, tmp); // Perform FFT, signal will have the result.
std::cout << "Printing the module of the obtained FFT coefficients:\n\nabs_FFT = [\n";
for (k = 0; k < N; k++) {
std::cout << std::sqrt((signal[k].Re*signal[k].Re+signal[k].Im*signal[k].Im)) << std::endl;
}
std::cout << "];\n\nDone. Check whether the second module is 32 and the 11th is 128\n";
std::cout << "2th: " << std::sqrt((signal[1].Re*signal[1].Re+signal[1].Im*signal[1].Im)) << std::endl;
std::cout << "11th: " << std::sqrt((signal[10].Re*signal[10].Re+signal[10].Im*signal[10].Im)) << std::endl;
std::cout << "(all the others must be zero, or close to zero)\n\n";
return 0;
}
Logging
#include <iostream>
#include <cmath>
#include "../../include/posit.h"
using namespace std;
using namespace posit;
using myreal = Posit<int16_t, 8, 0, uint16_t, PositSpec::WithNan>;
/**
* The posit class has a built-in value logger to trace
* the values that are assigned to the class during
* the execution of a given portion of code.
**/
int main() {
myreal a;
// 1. Enable the logger at the beginning of the portion of code to be traced
myreal::_logger.setLogLevel(LogLevel::ALL);
for(int i = 0; i < 100; ++i) {
a = myreal((double(i)/100));
}
// 2. Complete tracing by saving the traced values
myreal::_logger.save("a_logged.txt");
}
Pseudo-sigmoid
#include <iostream>
#include <cmath>
#include <posit.h>
using namespace std;
using namespace posit;
using Xa = Posit<int16_t, 16, 0, uint16_t, PositSpec::WithNan>;
typedef Xa myfl;
myfl sigmoid(myfl x) {
double a = double(x);
return 1/(1+std::exp(-a));
}
int main() {
myfl a[] = {myfl(0.90625f)
,myfl(0.2f)
,myfl(0.3f)
,myfl(0.4f)
,myfl(0.43f)};
cout << "Number" << " " << "Pseudosigmoid" << " " << "Sigmoid " << " " << "Difference" << "\n";
for(int i = 0; i < 5; ++i)
cout << a[i] << " " << double(a[i].pseudosigmoid()) << " " << double(sigmoid(a[i])) << " " << double(sigmoid(a[i]))-double(a[i].pseudosigmoid())<< "\n";
for(int i = 0; i < 5; ++i)
cout << -a[i] << " " << double((-a[i]).pseudosigmoid()) << " " << double(sigmoid(-a[i])) << " " << double(sigmoid(-a[i]))-double((-a[i]).pseudosigmoid())<< "\n";
return 0;
}
Pseudo-tanh
#include <iostream>
#include <cmath>
#include <posit.h>
using namespace std;
using namespace posit;
using Xa = Posit<int32_t,8,0,uint64_t,PositSpec::WithNan>;
typedef Xa myfl;
template <class T>
T tanh(T x) {
return std::tanh(double(x));
}
int main() {
myfl a[] = {0.90625f,
0.32312f,
0.333543f,
0.2132144f,
0.5213f,
-0.3f,
-0.2f,
-0.1f,
0.43f};
for(auto x: a)
cout << x << " " << double(x.pseudotanh()) << " " << tanh(x) << std::endl;
return 0;
}
Fused Operations
#include <iostream>
#include <vector>
using namespace std;
#include <posit.h> // include non-tabulated posits
using namespace posit;
int main() {
using ptype = Posit<int8_t, 8, 0, uint32_t, PositSpec::WithInfs>;
using paccum = Posit<int16_t,16,0,uint32_t, PositSpec::WithNan>;
std::vector<ptype> a{ptype(1.f),ptype(1.f),ptype(1.f),ptype(1.f),ptype(1.f),ptype(1.f)}; // constucts a posit, using a float literal
std::vector<ptype> b{ptype(1.f),ptype(1.f),ptype(1.f),ptype(1.f),ptype(1.f),ptype(1.f)}; // constucts a posit, using a float literal
paccum res(0);
auto pres = posit::math::fma_dot(a.begin(),b.begin(),a.size(),res);
std::cout << pres << std::endl;
return 0;
}
Hardware backend example
#include <iostream>
#include <vector>
using namespace std;
#include <posit.h>
using namespace posit;
#include <iomanip>
int main() {
using PPEMU = Posit<int32_t, 32, 2, uint32_t, PositSpec::WithInfs>;
using PP = Posit<int32_t, 32, 2, BackendXPosit<int32_t,PPEMU>, PositSpec::WithInfs>;
PP OneHalf(0.5f);
std::cout << OneHalf << std::endl;
return 0;
}