Commit 2fb077ca authored by Andrey Zgarbul's avatar Andrey Zgarbul

benches, readme

parent aef32507
......@@ -34,6 +34,7 @@ optional = true
[dev-dependencies]
rand = "0.6"
criterion = "0.2"
[features]
default = []
......@@ -44,3 +45,7 @@ nightly = []
[[example]]
name = "inverse"
required-features = ["rand"]
[[bench]]
name = "p32"
harness = false
[![crates.io](https://img.shields.io/crates/v/softposit.svg)](https://crates.io/crates/softposit)
[![crates.io](https://img.shields.io/crates/d/softposit.svg)](https://crates.io/crates/softposit)
# `softposit-rs`
## `softposit-rs`
Rust port of [SoftPosit] repository.
[SoftPosit]: https://gitlab.com/cerlane/SoftPosit
How to use see examples.
Such types are supported now:
* P32E2 or P32: 32-bit posit with exponent size ES=2;
* P16E1 or P16: 16-bit posit with ES=1;
* P8E0 or P8: 8-bit posit without exponent bits.
## Examples
### Convert from f64, Add
```
use softposit::P32;
fn main() {
let a = P32::from(12.3);
let b = P32::from(154.);
let c = a + b;
println!("c = {0} or c = {0:?}", c);
}
```
## Quire
Each Posit type has correspondent Quire type (Q32, Q16, Q8).
These types support `AddAssign` and `SubAssign` operations.
For example:
```
use softposit::{P32, Q32};
// c == 12.3*0.4 - 6.3*8.4 == -48;
fn main() {
let mut q = Q32::init();
q += (P32::from(12.3), P32::from(0.4));
q -= (P32::from(6.3), P32::from(8.4));
let c = q.to_posit();
println!("c = {0} or c = {0:?}", c);
}
```
## Math
Math functions, like trigonomentic, are partially implemented for P32E2 type.
For complex computations use `num::Complex` type.
## Linear algebra
You can also use matrix operations, defined in [nalgebra](https://crates.io/crates/nalgebra) crate
by using `linalg` feature:
```
use softposit::P32;
use nalgebra::{Dynamic, Matrix, VecStorage};
type DMatrix = Matrix<P32, Dynamic, Dynamic, VecStorage<P32, Dynamic, Dynamic>>;
fn main() {
let a = DMatrix::new_random(5, 5);
println!("Matrix A = {}", a);
let decomp = &a.clone().lu();
if let Some(c) = decomp.try_inverse() {
println!("Inverse matrix Aˉ¹ = {}", c);
println!("Check Identity");
let ones = a * c;
println!("A × Aˉ¹ = {}", ones);
} else {
println!("Matrix A can't be inverted");
}
}
```
```
cargo build --features="linalg,rand"
```
## Benchmarking
```
cargo bench
```
| Type | Operation | i3-2310M @ 2.10GHz | i5-3470 @ 3.20GHz |
| ----- |:---------:|:------------------:|:-----------------:|
| P32E2 | + | 47 MPOPS | 82 MPOPS |
| | - | 45 MPOPS | 83 MPOPS |
| | * | 56 MPOPS | 99 MPOPS |
| | / | 25 MPOPS | 42 MPOPS |
| | sqrt | 48 MPOPS | 92 MPOPS |
| | round | 89 MPOPS | 159 MPOPS |
use criterion::{criterion_group, criterion_main};
use criterion::{Criterion, black_box as bb};
use softposit::{P32, Q32};
fn criterion_benchmark(c: &mut Criterion) {
const X: P32 = P32::new(0x_5c80_0000); // 12.5
const Y: P32 = P32::new(0x_6b55_5810); // 117.334
const Z: P32 = P32::new(0x_3c2e_48e9); // 0.7613
c.bench_function("add", |c| c.iter(|| bb(X) + bb(Y)));
c.bench_function("sub", |c| c.iter(|| bb(X) - bb(Y)));
c.bench_function("mul", |c| c.iter(|| bb(X) * bb(Y)));
c.bench_function("div", |c| c.iter(|| bb(X) / bb(Y)));
c.bench_function("sqrt", |c| c.iter(|| bb(X).sqrt()));
c.bench_function("round", |c| c.iter(|| bb(Y).round()));
c.bench_function("sin", |c| c.iter(|| bb(Z).sin()));
c.bench_function("sin2", |c| c.iter(|| bb(Y).sin()));
c.bench_function("cos", |c| c.iter(|| bb(Z).cos()));
c.bench_function("tan", |c| c.iter(|| bb(Z).tan()));
c.bench_function("exp", |c| c.iter(|| bb(X).exp()));
c.bench_function("ln", |c| c.iter(|| bb(X).ln()));
c.bench_function("pow", |c| c.iter(|| bb(X).powf(Z)));
c.bench_function("q_add", |c| c.iter(|| {
let mut q = Q32::init();
q += (bb(X), bb(Y));
q.to_posit()
}));
c.bench_function("q_add3", |c| c.iter(|| {
let mut q = Q32::init();
q += (bb(X), bb(Y));
q += (bb(X), bb(Z));
q += (bb(Y), bb(Z));
q.to_posit()
}));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
......@@ -1036,7 +1036,7 @@ macro_rules! impl_alga {
}
#[macro_export]
macro_rules! add_sub_array {
macro_rules! quire_add_sub_array {
($posit:ty, $quire:ty, $($i:literal),*) => {$(
impl ops::AddAssign<($posit, [$posit; $i])> for $quire {
#[inline]
......@@ -1057,3 +1057,72 @@ macro_rules! add_sub_array {
}
)*}
}
#[macro_export]
macro_rules! quire_add_sub {
($posit:ty, $quire:ty) => {
impl ops::AddAssign<($posit, $posit)> for $quire {
#[inline]
fn add_assign(&mut self, rhs: ($posit, $posit)) {
fdp_add(self, rhs.0, rhs.1);
}
}
impl ops::AddAssign<($posit, ($posit, $posit))> for $quire {
#[inline]
fn add_assign(&mut self, rhs: ($posit, ($posit, $posit))) {
*self += (rhs.0, (rhs.1).0);
*self += (rhs.0, (rhs.1).1);
}
}
impl ops::AddAssign<$posit> for $quire {
#[inline]
fn add_assign(&mut self, rhs: $posit) {
*self += (rhs, <$posit>::ONE);
}
}
impl ops::AddAssign<(($posit, $posit), ($posit, $posit))> for $quire {
#[inline]
fn add_assign(&mut self, rhs: (($posit, $posit), ($posit, $posit))) {
*self += ((rhs.0).0, (rhs.1).0);
*self += ((rhs.0).0, (rhs.1).1);
*self += ((rhs.0).1, (rhs.1).0);
*self += ((rhs.0).1, (rhs.1).1);
}
}
impl ops::SubAssign<($posit, $posit)> for $quire {
#[inline]
fn sub_assign(&mut self, rhs: ($posit, $posit)) {
fdp_sub(self, rhs.0, rhs.1);
}
}
impl ops::SubAssign<$posit> for $quire {
#[inline]
fn sub_assign(&mut self, rhs: $posit) {
*self -= (rhs, <$posit>::ONE);
}
}
impl ops::SubAssign<($posit, ($posit, $posit))> for $quire {
#[inline]
fn sub_assign(&mut self, rhs: ($posit, ($posit, $posit))) {
*self -= (rhs.0, (rhs.1).0);
*self -= (rhs.0, (rhs.1).1);
}
}
impl ops::SubAssign<(($posit, $posit), ($posit, $posit))> for $quire {
#[inline]
fn sub_assign(&mut self, rhs: (($posit, $posit), ($posit, $posit))) {
*self -= ((rhs.0).0, (rhs.1).0);
*self -= ((rhs.0).0, (rhs.1).1);
*self -= ((rhs.0).1, (rhs.1).0);
*self -= ((rhs.0).1, (rhs.1).1);
}
}
}
}
......@@ -285,12 +285,12 @@ impl Q16E1 {
#[inline]
pub fn add_product(&mut self, p_a: P16E1, p_b: P16E1) {
ops::q16_fdp_add(self, p_a, p_b);
ops::fdp_add(self, p_a, p_b);
}
#[inline]
pub fn sub_product(&mut self, p_a: P16E1, p_b: P16E1) {
ops::q16_fdp_sub(self, p_a, p_b);
ops::fdp_sub(self, p_a, p_b);
}
#[inline]
......
......@@ -456,58 +456,10 @@ impl ops::Rem for P16E1 {
}
}
impl ops::AddAssign<(P16E1, P16E1)> for Q16E1 {
#[inline]
fn add_assign(&mut self, rhs: (P16E1, P16E1)) {
q16_fdp_add(self, rhs.0, rhs.1);
}
}
impl ops::AddAssign<(P16E1, (P16E1, P16E1))> for Q16E1 {
#[inline]
fn add_assign(&mut self, rhs: (P16E1, (P16E1, P16E1))) {
*self += (rhs.0, (rhs.1).0);
*self += (rhs.0, (rhs.1).1);
}
}
impl ops::AddAssign<((P16E1, P16E1), (P16E1, P16E1))> for Q16E1 {
#[inline]
fn add_assign(&mut self, rhs: ((P16E1, P16E1), (P16E1, P16E1))) {
*self += ((rhs.0).0, (rhs.1).0);
*self += ((rhs.0).0, (rhs.1).1);
*self += ((rhs.0).1, (rhs.1).0);
*self += ((rhs.0).1, (rhs.1).1);
}
}
impl ops::SubAssign<(P16E1, P16E1)> for Q16E1 {
#[inline]
fn sub_assign(&mut self, rhs: (P16E1, P16E1)) {
q16_fdp_sub(self, rhs.0, rhs.1);
}
}
impl ops::SubAssign<(P16E1, (P16E1, P16E1))> for Q16E1 {
#[inline]
fn sub_assign(&mut self, rhs: (P16E1, (P16E1, P16E1))) {
*self -= (rhs.0, (rhs.1).0);
*self -= (rhs.0, (rhs.1).1);
}
}
impl ops::SubAssign<((P16E1, P16E1), (P16E1, P16E1))> for Q16E1 {
#[inline]
fn sub_assign(&mut self, rhs: ((P16E1, P16E1), (P16E1, P16E1))) {
*self -= ((rhs.0).0, (rhs.1).0);
*self -= ((rhs.0).0, (rhs.1).1);
*self -= ((rhs.0).1, (rhs.1).0);
*self -= ((rhs.0).1, (rhs.1).1);
}
}
crate::add_sub_array!(P16E1, Q16E1, 1, 2, 3, 4);
crate::quire_add_sub!(P16E1, Q16E1);
crate::quire_add_sub_array!(P16E1, Q16E1, 1, 2, 3, 4);
pub(super) fn q16_fdp_add(q: &mut Q16E1, p_a: P16E1, p_b: P16E1) {
pub(super) fn fdp_add(q: &mut Q16E1, p_a: P16E1, p_b: P16E1) {
let u_z1 = q.to_bits();
let mut ui_a = p_a.to_bits();
......@@ -617,7 +569,7 @@ pub(super) fn q16_fdp_add(q: &mut Q16E1, p_a: P16E1, p_b: P16E1) {
*q = if q_z.is_nar() { Q16E1::ZERO } else { q_z }
}
pub(super) fn q16_fdp_sub(q: &mut Q16E1, p_a: P16E1, p_b: P16E1) {
pub(super) fn fdp_sub(q: &mut Q16E1, p_a: P16E1, p_b: P16E1) {
let u_z1 = q.to_bits();
let mut ui_a = p_a.to_bits();
......
......@@ -285,12 +285,12 @@ impl Q32E2 {
#[inline]
pub fn add_product(&mut self, p_a: P32E2, p_b: P32E2) {
ops::q32_fdp_add(self, p_a, p_b);
ops::fdp_add(self, p_a, p_b);
}
#[inline]
pub fn sub_product(&mut self, p_a: P32E2, p_b: P32E2) {
ops::q32_fdp_sub(self, p_a, p_b);
ops::fdp_sub(self, p_a, p_b);
}
#[inline]
......
......@@ -481,58 +481,10 @@ impl ops::Rem for P32E2 {
}
}
impl ops::AddAssign<(P32E2, P32E2)> for Q32E2 {
#[inline]
fn add_assign(&mut self, rhs: (P32E2, P32E2)) {
q32_fdp_add(self, rhs.0, rhs.1);
}
}
impl ops::AddAssign<(P32E2, (P32E2, P32E2))> for Q32E2 {
#[inline]
fn add_assign(&mut self, rhs: (P32E2, (P32E2, P32E2))) {
*self += (rhs.0, (rhs.1).0);
*self += (rhs.0, (rhs.1).1);
}
}
impl ops::AddAssign<((P32E2, P32E2), (P32E2, P32E2))> for Q32E2 {
#[inline]
fn add_assign(&mut self, rhs: ((P32E2, P32E2), (P32E2, P32E2))) {
*self += ((rhs.0).0, (rhs.1).0);
*self += ((rhs.0).0, (rhs.1).1);
*self += ((rhs.0).1, (rhs.1).0);
*self += ((rhs.0).1, (rhs.1).1);
}
}
impl ops::SubAssign<(P32E2, P32E2)> for Q32E2 {
#[inline]
fn sub_assign(&mut self, rhs: (P32E2, P32E2)) {
q32_fdp_sub(self, rhs.0, rhs.1);
}
}
impl ops::SubAssign<(P32E2, (P32E2, P32E2))> for Q32E2 {
#[inline]
fn sub_assign(&mut self, rhs: (P32E2, (P32E2, P32E2))) {
*self -= (rhs.0, (rhs.1).0);
*self -= (rhs.0, (rhs.1).1);
}
}
impl ops::SubAssign<((P32E2, P32E2), (P32E2, P32E2))> for Q32E2 {
#[inline]
fn sub_assign(&mut self, rhs: ((P32E2, P32E2), (P32E2, P32E2))) {
*self -= ((rhs.0).0, (rhs.1).0);
*self -= ((rhs.0).0, (rhs.1).1);
*self -= ((rhs.0).1, (rhs.1).0);
*self -= ((rhs.0).1, (rhs.1).1);
}
}
crate::add_sub_array!(P32E2, Q32E2, 1, 2, 3, 4);
crate::quire_add_sub!(P32E2, Q32E2);
crate::quire_add_sub_array!(P32E2, Q32E2, 1, 2, 3, 4);
pub(super) fn q32_fdp_add(q: &mut Q32E2, p_a: P32E2, p_b: P32E2) {
pub(super) fn fdp_add(q: &mut Q32E2, p_a: P32E2, p_b: P32E2) {
let u_z1 = q.to_bits();
let mut ui_a = p_a.to_bits();
......@@ -642,7 +594,7 @@ pub(super) fn q32_fdp_add(q: &mut Q32E2, p_a: P32E2, p_b: P32E2) {
*q = if q_z.is_nar() { Q32E2::ZERO } else { q_z }
}
pub(super) fn q32_fdp_sub(q: &mut Q32E2, p_a: P32E2, p_b: P32E2) {
pub(super) fn fdp_sub(q: &mut Q32E2, p_a: P32E2, p_b: P32E2) {
let u_z1 = q.to_bits();
let mut ui_a = p_a.to_bits();
......
......@@ -263,12 +263,12 @@ impl Q8E0 {
#[inline]
pub fn add_product(&mut self, p_a: P8E0, p_b: P8E0) {
ops::q8_fdp_add(self, p_a, p_b);
ops::fdp_add(self, p_a, p_b);
}
#[inline]
pub fn sub_product(&mut self, p_a: P8E0, p_b: P8E0) {
ops::q8_fdp_sub(self, p_a, p_b);
ops::fdp_sub(self, p_a, p_b);
}
#[inline]
......
......@@ -371,58 +371,10 @@ impl ops::Rem for P8E0 {
}
}
impl ops::AddAssign<(P8E0, P8E0)> for Q8E0 {
#[inline]
fn add_assign(&mut self, rhs: (P8E0, P8E0)) {
q8_fdp_add(self, rhs.0, rhs.1);
}
}
impl ops::AddAssign<(P8E0, (P8E0, P8E0))> for Q8E0 {
#[inline]
fn add_assign(&mut self, rhs: (P8E0, (P8E0, P8E0))) {
*self += (rhs.0, (rhs.1).0);
*self += (rhs.0, (rhs.1).1);
}
}
impl ops::AddAssign<((P8E0, P8E0), (P8E0, P8E0))> for Q8E0 {
#[inline]
fn add_assign(&mut self, rhs: ((P8E0, P8E0), (P8E0, P8E0))) {
*self += ((rhs.0).0, (rhs.1).0);
*self += ((rhs.0).0, (rhs.1).1);
*self += ((rhs.0).1, (rhs.1).0);
*self += ((rhs.0).1, (rhs.1).1);
}
}
impl ops::SubAssign<(P8E0, P8E0)> for Q8E0 {
#[inline]
fn sub_assign(&mut self, rhs: (P8E0, P8E0)) {
q8_fdp_sub(self, rhs.0, rhs.1);
}
}
impl ops::SubAssign<(P8E0, (P8E0, P8E0))> for Q8E0 {
#[inline]
fn sub_assign(&mut self, rhs: (P8E0, (P8E0, P8E0))) {
*self -= (rhs.0, (rhs.1).0);
*self -= (rhs.0, (rhs.1).1);
}
}
impl ops::SubAssign<((P8E0, P8E0), (P8E0, P8E0))> for Q8E0 {
#[inline]
fn sub_assign(&mut self, rhs: ((P8E0, P8E0), (P8E0, P8E0))) {
*self -= ((rhs.0).0, (rhs.1).0);
*self -= ((rhs.0).0, (rhs.1).1);
*self -= ((rhs.0).1, (rhs.1).0);
*self -= ((rhs.0).1, (rhs.1).1);
}
}
crate::add_sub_array!(P8E0, Q8E0, 1, 2, 3, 4);
crate::quire_add_sub!(P8E0, Q8E0);
crate::quire_add_sub_array!(P8E0, Q8E0, 1, 2, 3, 4);
pub(super) fn q8_fdp_add(q: &mut Q8E0, p_a: P8E0, p_b: P8E0) {
pub(super) fn fdp_add(q: &mut Q8E0, p_a: P8E0, p_b: P8E0) {
let uq_z1 = q.to_bits();
let mut ui_a = p_a.to_bits();
......@@ -481,7 +433,7 @@ pub(super) fn q8_fdp_add(q: &mut Q8E0, p_a: P8E0, p_b: P8E0) {
//q - (p_a*p_b)
pub(super) fn q8_fdp_sub(q: &mut Q8E0, p_a: P8E0, p_b: P8E0) {
pub(super) fn fdp_sub(q: &mut Q8E0, p_a: P8E0, p_b: P8E0) {
let uq_z1 = q.to_bits();
let mut ui_a = p_a.to_bits();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment