2
\$\begingroup\$

A Lychrel number is a natural number that cannot form a palindrome through the iterative process of repeatedly reversing its digits and adding the resulting numbers.

In the code below I'm trying to calculate the palindrome that comes from the end of this algorithm up to some limit (as it is hypothesized to be infinite for some values).

extern crate num;
extern crate time;

use num::bigint::BigInt;
use num::FromPrimitive;
use time::PreciseTime;
use std::env;

// The limit for number of iterations to run.
static LIMIT: u64 = 5000;

// Return the "lychrel" number for a given input, or the number reached
// at iteration LIMIT, whichever comes first.
fn lychrel(number: u64) -> BigInt {
    let mut next = FromPrimitive::from_u64(number).unwrap();
    let mut iterations = 0;
    let mut rev;

    loop {
        // rev = reverse(&next, &zero);
        rev = reverse_str(&next);

        if &next == &rev {
            break;
        }

        next = &next + &rev;

        if iterations % 1000 == 0 { println!("{} iterations complete.", iterations) }
        if iterations == LIMIT { break; }

        iterations += 1;
    }

    next
}

// Integer function is nearly 4 (!) times slower.
// So this function has been removed, in favour of reverse_str()
// fn reverse(number: &BigInt, zero: &BigInt) -> BigInt {
//  let zero: BigInt = FromPrimitive::from_u64(0).unwrap();
//  let mut reverse = FromPrimitive::from_u64(0).unwrap();
//  let mut temp = number.clone();

//  while &temp > &zero {
//      reverse = reverse * 10 + &temp % 10;
//      temp = &temp / 10;
//  }

//  reverse
// }

// Transform a BigInt into a char array, reverse and parse back into a BigInt.
fn reverse_str(number: &BigInt) -> BigInt {
    let reverse_string: String = number.to_string().chars().rev().collect();
    let reverse_value: BigInt = reverse_string.parse().unwrap();
    number + reverse_value
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let start = PreciseTime::now();

    let input = args[1].parse::<u64>().expect("Usage: ./lychrel <number>");

    lychrel(input);
    // println!("{}", lychrel(input));

    let end = PreciseTime::now();
    println!("Processed {} iterations in {} seconds.", LIMIT, start.to(end));
}

(Note that this requires the num and time crates to be installed)

This is my first time using Rust, so I'm finding the entire idea of "ownership" pretty new. Am I passing data by reference too much? I seem to have a lot of ampersands.

\$\endgroup\$
  • 1
    \$\begingroup\$ As already mentioned in the answer, you probably want to return just reverse_value in reverse_str, otherwise it's bugged. \$\endgroup\$ – E_net4 on strike Nov 28 '17 at 0:28
  • \$\begingroup\$ @E_net4 Oooh! Nice catch! I wrote this in both JavaScript & Python before converting it to Rust. I kidded myself into thinking "all give the same answer, so it must be right". Tests are important :') \$\endgroup\$ – Alexander Craggs Nov 28 '17 at 0:58
3
\$\begingroup\$
  1. Use const instead of static if you don't need to take the address of the global.

  2. Use for over a range instead of mutating a counter.

  3. It's a little strange to return a value when the iteration runs out. Perhaps an Option would be better?

  4. There's no need to take references just to compare for equality; eq takes &self.

  5. Don't need &next or &rev when adding to get next because we no longer need these values.

  6. reverse_str does more than just reverse; perhaps a better name is in order?

  7. No need to collect all the arguments to an array, just use the iterator directly.

extern crate num;
extern crate time;

use num::bigint::BigInt;
use num::FromPrimitive;
use time::PreciseTime;
use std::env;

const LIMIT: u64 = 5000;

fn lychrel(number: u64) -> BigInt {
    let mut next = FromPrimitive::from_u64(number).unwrap();
    let mut rev;

    for i in 0..LIMIT {
        rev = reverse_str(&next);

        if next == rev {
            break;
        }

        next = next + rev;

        if i % 1000 == 0 {
            println!("{} iterations complete.", i)
        }
    }

    next
}

fn reverse_str(number: &BigInt) -> BigInt {
    let reverse_string: String = number.to_string().chars().rev().collect();
    let reverse_value: BigInt = reverse_string.parse().unwrap();
    number + reverse_value
}

fn main() {
    let arg = env::args().nth(1).expect("Usage: ./lychrel <number>");

    let start = PreciseTime::now();
    let input = arg.parse::<u64>().expect("Argument must be a number");
    lychrel(input);
    let end = PreciseTime::now();

    println!("Processed {} iterations in {} seconds.", LIMIT, start.to(end));
}

I think it would be interesting to convert the iteration to an iterator.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.