I'm trying to learn Rust, and I'm slowly starting to realize how much fun it is. I want a function
- allocate the main array of variable length (in the general sense of the word, not necessarily the type Rust) floats on the heap
- initialize it with values
- implement drop, so I don’t have to worry about freeing memory and something for indexing or iteration.
The obvious choice is Vec , but how does it compare to a piece in the heap? Vec more powerful, but I need an array for numerical mathematics and, in my case, I don’t need things like push / pop. The idea is to have something with less features, but faster.
Below I have two versions of the "linspace" function (a la Matlab and numpy),
- "linspace_vec" (see list below) uses
Vec - "linspace_boxed_slice" (see list below) uses a slice in a box
Both are used as
let y = linspace_*(start, stop, len);
where y is a linearly spaced "array" (i.e., a Vec in (1) and an insert in a block in (2)) of length len.
Now the question is: for small "arrays" of length 1000, (1) is FASTER. For large arrays 4 * 10 ^ 6 long, (1) is SLOWER. Why is this? Am I doing something wrong in (2)?
When the argument is len = 1000, comparative analysis by simply calling the function leads to
- (1) ... bench: 879 ns / iter (+/- 12)
- (2) ... bench: 1,295 ns / iter (+/- 38)
When the argument len = 4000000, the comparison results in
- (1) ... bench: 5 802 836 ns / iner (+/- 90.209)
- (2) ... bench: 4,767,234 ns / iner (+/- 121,596)
List (1):
pub fn linspace_vec<'a, T: 'a>(start: T, stop: T, len: usize) -> Vec<T> where T: Float { // get 0, 1 and the increment dx as T let (one, zero, dx) = get_values_as_type_t::<T>(start, stop, len); let mut v = vec![zero; len]; let mut c = zero; let ptr: *mut T = v.as_mut_ptr(); unsafe { for ii in 0..len { let x = ptr.offset((ii as isize)); *x = start + c*dx; c = c + one; } } return v }
Listing (2):
pub fn linspace_boxed_slice<'a, T: 'a>(start: T, stop: T, len: usize) -> Box<&'a mut [T]> where T: Float { let (one, zero, dx) = get_values_as_type_t::<T>(start, stop, len); let size = len * mem::size_of::<T>(); unsafe { let ptr = heap::allocate(size, align_of::<T>()) as *mut T; let mut c = zero; for ii in 0..len { let x = ptr.offset((ii as isize)); *x = start + c*dx; c = c + one; } // IS THIS WHAT MAKES IT SLOW?: let sl = slice::from_raw_parts_mut(ptr, len); return Box::new(sl); } }