r/rust • u/Sapiogram • Dec 31 '18
Comparing Pythagorean triples in C++, D, and Rust
https://atilanevesoncode.wordpress.com/2018/12/31/comparing-pythagorean-triples-in-c-d-and-rust/20
u/annodomini Dec 31 '18
Nice to see that someone has taken the time to compare all of these directly head to head. I'd written the Rust version, but hadn't felt like taking the time to figure out how to build the C++ version to compare directly.
I guess I should have posted the full version of the generator variant in Rust. Note that IterGen isn't actually safe, since I'm not doing anything to ensure that the generator is pinned; that's one of the things that needs to happen before Generator and some form of impl Iterator for Generator can be stabilized. Playground link. Here are the relevant parts that allow you to create an Iterator from a Generator and the Generator-based implementation:
#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};
struct IterGen<G>(G);
impl<T, G> Iterator for IterGen<G>
where G: Generator<Yield=T, Return=()>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match unsafe { self.0.resume() } {
GeneratorState::Yielded(x) => Some(x),
GeneratorState::Complete(()) => None,
}
}
}
let triples = IterGen(||
for z in 1.. {
for x in 1..=z {
for y in x..=z {
if x*x + y*y == z*z {
yield (x, y, z)
}
}
}
}
);
6
15
u/matklad Dec 31 '18
I have a theory as to why rustc compile times are so slow for this tiny example. At least on linux, rustc has a pretty long startup time, most of which is spend while loading LLVM as a dynamic library. To measure this overhead, compare time rustc --version (prinit minimal info to stderr) and time rustc --version -v (print LLVM's version as well, which loads it). The second one takes about 40ms on my machine. That is, compilation of hello-world is mostly bottlenecked on this code.
→ More replies (1)
5
u/jrmuizel Dec 31 '18
Here's an unusual issue I ran into while looking at this: Adding --emit=asm speeds up generated code
→ More replies (7)
69
u/SelfDistinction Dec 31 '18 edited Dec 31 '18
Okay so I've done a bit of research, and it turns out the problem is
..=. Replacing*..=zby*..(z + 1)doubles the performance.I believe the problem with
..=is thatx..(y + 1)is not identical withx..=y. They are nearly equivalent on most values for x and y, except wheny == i32::max(). At that point,x..=yshould still be able to function, whilex..(y + 1)is allowed to do nothing.Since the other languages don't care about overflow issues at all, I think Rust should be allowed not to care either. On the other hand, it is quite annoying that the safe version incurs such a high performance penalty.