How to fix rust operations not working as expected? - rust

I have implemented a simple command-line calculator in Rust. The add function acts as normal but the subtract, multiply, and divide functions don't work. The rest of the code is on GitHub: https://github.com/henryboisdequin/rust-calculator.
calc.rs
impl Calc {
pub fn add(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total += num as f64;
}
total
}
pub fn sub(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total -= num as f64;
}
total
}
pub fn mul(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total *= num as f64;
}
total
}
pub fn div(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total /= num as f64;
}
total
}
}

Instead of having your functions take Vec<i64>, I would instead suggest &[i64], or even &[f64] to avoid the as f64. This wouldn't really break your existing code, as you can just borrow a Vec<i64>, to have it auto dereference into &[i64].
You can simplify add() by using sum(), and mul() by using product().
pub fn add(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).sum()
}
pub fn mul(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).product()
}
You can similarly simplify sub() and div() with next() and then fold().
pub fn sub(arr: &[i64]) -> f64 {
let mut it = arr.iter().map(|&x| x as f64);
it.next()
.map(|x| it.fold(x, |acc, x| acc - x))
.unwrap_or(0.0)
}
pub fn div(arr: &[i64]) -> f64 {
let mut it = arr.iter().map(|&x| x as f64);
it.next()
.map(|x| it.fold(x, |acc, x| acc / x))
.unwrap_or(0.0)
}
You can even simplify them further, by using fold_first(). However that is currently experimental and nightly only. Instead you can use fold1() from the itertools crate, or reduce() from the reduce crate.
// itertools = "0.10"
use itertools::Itertools;
pub fn sub(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(|a, b| a - b).unwrap_or(0.0)
}
pub fn div(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(|a, b| a / b).unwrap_or(0.0)
}
You can even replace the closures with Sub::sub and Div::div.
// itertools = "0.10"
use itertools::Itertools;
use std::ops::{Div, Sub};
pub fn sub(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(Sub::sub).unwrap_or(0.0)
}
pub fn div(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(Div::div).unwrap_or(0.0)
}

Siguza helped me fix this problem by specifying that my addition function only works because addition is commutative but the other operations are failing because they are not.
Here is the right code:
pub struct Calc;
impl Calc {
pub fn add(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total += num as f64;
}
total
}
pub fn sub(arr: Vec<i64>) -> f64 {
let mut total: f64 = arr[0] as f64;
let mut counter = 0;
while counter != arr.len() - 1 {
total -= arr[counter + 1] as f64;
counter += 1;
}
total
}
pub fn mul(arr: Vec<i64>) -> f64 {
let mut total: f64 = arr[0] as f64;
let mut counter = 0;
while counter != arr.len() - 1 {
total *= arr[counter + 1] as f64;
counter += 1;
}
total
}
pub fn div(arr: Vec<i64>) -> f64 {
let mut total: f64 = arr[0] as f64;
let mut counter = 0;
while counter != arr.len() - 1 {
total /= arr[counter + 1] as f64;
counter += 1;
}
total
}
}
For the operations excluding 0, instead of assigning the total to 0.0, I assigned the total to the first element of the given array and -/*// the total with the rest of the elements in the array.

Related

Writing rust function with traits working for Vec and array []

I would like to implement a function in rust, computing the norm of an array or Vec
for an Vec<f64> I would write the function as
pub fn vector_norm( vec_a : &Vec<f64> ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
and for an &[f64] I would do
pub fn vector_norm( vec_a : &[f64] ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
But is there a way to combine both versions into a single function by the use of traits. I was thinking of something like
pub fn vector_norm<T:std::iter::ExactSizeIterator>
( vec_a : &T ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
This does not work because the the template parameter T is not indexable. Is it possible to do this somehow?? Maybe with an iterator trait or something?
First of all, Vec<T> implements Deref for [T]. This means that &Vec<f64> can be implicitly converted into &[f64]. So, just taking in a &[f64] will work:
fn vector_norm(vec_a: &[f64]) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len() {
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
fn main() {
let my_vec = vec![1.0, 2.0, 3.0];
// &my_vec is implicitly converted to &[f64]
println!("{:?}", vector_norm(&my_vec));
}
However, if you want to broaden the acceptable values even further to all slice-like types, perhaps AsRef may be of use:
fn vector_norm<T: AsRef<[f64]>>(vec_a: T) -> f64 {
// use AsRef to get a &[f64]
let vec_a: &[f64] = vec_a.as_ref();
let mut norm = 0 as f64;
for i in 0..vec_a.len() {
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
fn main() {
let my_vec = vec![1.0, 2.0, 3.0];
println!("{:?}", vector_norm(&my_vec));
}
In addition to Aplet's answer, I'd add that if you're taking something that is only going to be used in a for _ in loop, you might want to look at IntoIterator.
fn vector_norm<T: IntoIterator<Item = f64>>(t: T) -> f64 {
let mut norm = 0f64;
for i in t {
norm += i * i;
}
norm.sqrt()
}
When you write for i in t, the compiler rewrites that into something that looks a bit more like this:
let mut iter = t.into_iter();
loop {
match iter.next() {
None => break,
Some(i) => {
// loop body
}
}
}
So if you only want to constrain your input as "something that works in a for loop", IntoIterator is the trait you're looking for.

Solving shuffle the array problem on leetcode in Rust

fn shuffle(nums: Vec<i32>, n: i32) -> Vec<i32> {
let mut res: Vec<i32>;
let mut i = 0;
while i < n {
res.push(nums[i]);
res.push(nums[n + i]);
i += 1;
}
res
}
When I try to index the nums array to get a value at [i], I get this error:
the type [i32] cannot be indexed by i32
the trait SliceIndex<[i32]> is not implemented for i32
required because of the requirements on the impl of Index<i32> for Vec<i32>
Any ideas how to solve this?
You can only index Vec using usizes, so you have to cast your i32s to usizes in order to index into nums:
fn shuffle(nums: Vec<i32>, n: i32) -> Vec<i32> {
let mut res = Vec::new();
let mut i = 0;
while i < n {
res.push(nums[i as usize]);
res.push(nums[(n + i) as usize]);
i += 1;
}
res
}
playground

How can I convert a f64 to f32 and get the closest approximation and the next greater or smaller value?

Possible pseudocode for the operation could be:
fn f32_greater(x: f64) -> f32 {
let mut y = x as f32; //I get closest
while f64::from(y) < x {
y = nextafter(y, f32::INFINITY);
}
y
}
fn f32_smaller(x: f64) -> f32 {
let mut y = x as f32; //I get closest
while f64::from(y) > x {
y = nextafter(y, f32::NEG_INFINITY);
}
y
}
I can not find an equivalent to C11's nextafter function in the libc crate or in the methods on f64
For context, I have an R-tree index using f32. I want to search the region with coordinates provided as a f64, so I need the smallest possible region in f32 that includes the f64 value.
This function was removed from the standard library. A solution could be to use the float_extras crate, but I don't really like the way of this crate so here my solution:
mod float {
use libc::{c_double, c_float};
use std::{f32, f64};
#[link_name = "m"]
extern "C" {
pub fn nextafter(x: c_double, y: c_double) -> c_double;
pub fn nextafterf(x: c_float, y: c_float) -> c_float;
// long double nextafterl(long double x, long double y);
// double nexttoward(double x, long double y);
// float nexttowardf(float x, long double y);
// long double nexttowardl(long double x, long double y);
}
pub trait NextAfter {
fn next_after(self, y: Self) -> Self;
}
impl NextAfter for f32 {
fn next_after(self, y: Self) -> Self {
unsafe { nextafterf(self, y) }
}
}
impl NextAfter for f64 {
fn next_after(self, y: Self) -> Self {
unsafe { nextafter(self, y) }
}
}
pub trait Succ {
fn succ(self) -> Self;
}
impl Succ for f32 {
fn succ(self) -> Self {
self.next_after(f32::INFINITY)
}
}
impl Succ for f64 {
fn succ(self) -> Self {
self.next_after(f64::INFINITY)
}
}
pub trait Pred {
fn pred(self) -> Self;
}
impl Pred for f32 {
fn pred(self) -> Self {
self.next_after(f32::NEG_INFINITY)
}
}
impl Pred for f64 {
fn pred(self) -> Self {
self.next_after(f64::NEG_INFINITY)
}
}
}
use crate::float::{Pred, Succ};
use num_traits::cast::{FromPrimitive, ToPrimitive};
fn f32_greater<T>(x: T) -> Option<f32>
where
T: ToPrimitive + FromPrimitive + std::cmp::PartialOrd,
{
let mut y = x.to_f32()?;
while T::from_f32(y)? < x {
y = y.succ();
}
Some(y)
}
fn f32_smaller<T>(x: T) -> Option<f32>
where
T: ToPrimitive + FromPrimitive + std::cmp::PartialOrd,
{
let mut y = x.to_f32()?;
while T::from_f32(y)? > x {
y = y.pred();
}
Some(y)
}
fn main() {
let a = 42.4242424242424242;
println!(
"{:.16?} < {:.16} < {:.16?}",
f32_smaller(a),
a,
f32_greater(a)
);
}
I don't understand why they don't include it in the num crate.

How to pass multiple args to a rust closure - expected closure that takes 1 argument

I am new to closures and I don't understand why I am getting the following error.
If I don't include the second argument its works:
fn obj_x(x: Vec<f64>) -> f64 {
return 0.0;
};
let f = |x: &Vec<f64>| obj_x(x.to_vec());
Here is my closure:
fn foo() {
let f = |x: &Vec<f64>, N: usize| obj_x(x.to_vec(), N);
}
fn obj_x(x: Vec<f64>, N: usize) -> f64 {
let x = (x[0] + 4.0).powf(2.0);
return x;
}
But unfortunately it fails
error[E0593]: closure is expected to take 1 argument, but it takes 2 arguments
--> src/main.rs:120:44
|
114 | let f = |x: &Vec<f64>, N: usize | obj_x(x.to_vec(),N);
| ------------------------- takes 2 arguments
...
120 | let mut fmin = Funcmin::new(&mut x,&f,&g,"cg");
| ^^ expected closure that takes 1 argument
|
Here is my full code:
fn obj_x(x: Vec<f64>, N: usize) -> f64 {
let x = (x[0] + 4.0).powf(2.0);
return x;
}
fn gradient_x(x: Vec<f64>) -> Vec<f64> {
return vec![2.0 * (x[0] + 4.0)];
}
fn test() {
let f = |x: &Vec<f64>, &N: usize| obj_x(x.to_vec(), N);
let g = |x: &Vec<f64>| gradient_x(x.to_vec());
let mut x = vec![40.0f64];
let mut N = 2220;
{
//you must create a mutable object
let mut fmin = Funcmin::new(&mut x, &f, &g, "cg");
fmin.minimize();
}
println!("{:?}", x);
}
This solution worked for me: declare
fn fold(n: u32, init: u32, op: impl Fn(u32, u32) -> u32) -> u32 {...
and call it as
fold(n, 1, |x: u32, y: u32| -> u32 {x + y })

Extend Iterator with a "mean" method

I'm trying to implement a mean method for Iterator, like it is done with sum.
However, sum is Iterator method, so I decided to implement trait for any type that implements Iterator:
pub trait Mean<A = Self>: Sized {
fn mean<I: Iterator<Item = A>>(iter: I) -> f64;
}
impl Mean for u64 {
fn mean<I: Iterator<Item = u64>>(iter: I) -> f64 {
//use zip to start enumeration from 1, not 0
iter.zip((1..))
.fold(0., |s, (e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
}
}
impl<'a> Mean<&'a u64> for u64 {
fn mean<I: Iterator<Item = &'a u64>>(iter: I) -> f64 {
iter.zip((1..))
.fold(0., |s, (&e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
}
}
trait MeanIterator: Iterator {
fn mean(self) -> f64;
}
impl<T: Iterator> MeanIterator for T {
fn mean(self) -> f64 {
Mean::mean(self)
}
}
fn main() {
assert_eq!([1, 2, 3, 4, 5].iter().mean(), 3.);
}
Playground
The error:
error[E0282]: type annotations needed
--> src/main.rs:26:9
|
26 | Mean::mean(self)
| ^^^^^^^^^^ cannot infer type for `Self`
Is there any way to fix the code, or it is impossible in Rust?
like it is done with sum
Let's review how sum works:
pub fn sum<S>(self) -> S
where
S: Sum<Self::Item>,
sum is implemented on any iterator, so long as the result type S implements Sum for the iterated value. The caller gets to pick the result type. Sum is defined as:
pub trait Sum<A = Self> {
pub fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = A>;
}
Sum::sum takes an iterator of A and produces a value of the type it is implemented from.
We can copy-paste the structure, changing Sum for Mean and put the straightforward implementations:
trait MeanExt: Iterator {
fn mean<M>(self) -> M
where
M: Mean<Self::Item>,
Self: Sized,
{
M::mean(self)
}
}
impl<I: Iterator> MeanExt for I {}
trait Mean<A = Self> {
fn mean<I>(iter: I) -> Self
where
I: Iterator<Item = A>;
}
impl Mean for f64 {
fn mean<I>(iter: I) -> Self
where
I: Iterator<Item = f64>,
{
let mut sum = 0.0;
let mut count: usize = 0;
for v in iter {
sum += v;
count += 1;
}
if count > 0 {
sum / (count as f64)
} else {
0.0
}
}
}
impl<'a> Mean<&'a f64> for f64 {
fn mean<I>(iter: I) -> Self
where
I: Iterator<Item = &'a f64>,
{
iter.copied().mean()
}
}
fn main() {
let mean: f64 = [1.0, 2.0, 3.0].iter().mean();
println!("{:?}", mean);
let mean: f64 = std::array::IntoIter::new([-1.0, 2.0, 1.0]).mean();
println!("{:?}", mean);
}
You can do it like this, for example:
pub trait Mean {
fn mean(self) -> f64;
}
impl<F, T> Mean for T
where T: Iterator<Item = F>,
F: std::borrow::Borrow<f64>
{
fn mean(self) -> f64 {
self.zip((1..))
.fold(0.,
|s, (e, i)| (*e.borrow() + s * (i - 1) as f64) / i as f64)
}
}
fn main() {
assert_eq!([1f64, 2f64, 3f64, 4f64, 5f64].iter().mean(), 3.);
assert_eq!(vec![1f64, 2f64, 3f64, 4f64, 5f64].iter().mean(), 3.);
assert_eq!(vec![1f64, 2f64, 3f64, 4f64, 5f64].into_iter().mean(), 3.);
}
I used Borrow trait to support iterators over f64 and &f64.

Resources