Multiplicative persistence lets me learn Rust.

Multiplicative persistence lets me learn Rust.

This is a coding exercise that I am starting for myself where I try to find cool math thingies(cool according to me, not a general definition of course) and try to code it in a language I am not familiar with, so that not only I can have fun but will also learn.

So multiplicative persistence of a number is the number of iterations you need to go through of multiplying the digits of the number until you get a single digit value. The main inspiration for this topic is a Numberphile video:

For example if we take 463

4 x 6 x 3 = 72

7 x 2 = 14

1 x 4 = 4

So it took 3 iterations, so multiplicative persistence of 463 is 3.

Although finding multiplicative persistence of a number is fairly straightforward, what I want to do here, just like the video is given the persistence, find the smallest number with that number as the multiplicative persistence. So for instance for 3 that would be 39. For 4 it would be 77 and so on.

My plan is to write this program in rust, but of course I have zero idea about it, so I shall start by writing a sample function in my favourite language which is python.

import time

def digit_product(n):
    result = 1
    while n > 0:
        digit = n % 10
        result *= digit
        n //= 10
    return result

def find_minimum_with_multiplicative_persistence(target_persistence):
    start_time = time.time()

    number = 1
    while True:
        current_number = number
        current_persistence = 0

        while current_number >= 10:
            current_number = digit_product(current_number)
            current_persistence += 1

        if current_persistence == target_persistence:
            end_time = time.time()
            elapsed_time = end_time - start_time
            print(f"Time taken to find result: {elapsed_time} seconds")
            return number

        number += 1

Currently this is a very unoptimised code that just check each and every number, which is not the best way to do it, as there are ways to reduce the search space significantly but I wanted to write this in one go, so I would like to take suggestions from you guys if you have any to do the said optimisation.

One obvious thing that we can do to speed things up is code it in a language that's significantly and that is exactly what I did here by writing the same code in rust.

use std::time::{Instant};

fn digit_product(mut n: u64) -> u64 {
    let mut result = 1;
    while n > 0 {
        let digit = n % 10;
        result *= digit;
        n /= 10;
    }
    result
}

fn find_minimum_with_multiplicative_persistence(target_persistence: u64) -> u64 {
    let start_time = Instant::now();

    let mut number = 1;
    loop {
        let mut current_number = number;
        let mut current_persistence = 0;

        while current_number >= 10 {
            current_number = digit_product(current_number);
            current_persistence += 1;
        }

        if current_persistence == target_persistence {
            let elapsed_time = start_time.elapsed();
            println!("Time taken to find result: {:?}", elapsed_time);
            return number;
        }

        number += 1;
    }
}

fn main() {
    let target_persistence = 8;
    let result = find_minimum_with_multiplicative_persistence(target_persistence);
    println!("The smallest number with multiplicative persistence {} is: {}", target_persistence, result);
}

If we compare the time it takes for python and rust to calculate the minimum number with multiplicative persistence as 9, for python it takes around 30 seconds, whereas rust does it in 4.6 seconds.

I did try to find it for 10 as well, but unfortunately python took too long and lost patience whereas rust took 849 seconds.

As I was waiting for the other codes to run, I decided to write the code in Julia too as it is known to be pretty quick in doing math and as results show, I was right too!!! It was just insanely quick in doing the operations, too good honestly. Of course, maybe I should have spent more time on optimising the code in other languages, instead of running behind new languages and writing the same code, but I was having fun, so I just went with it.

function digit_product(n)
    result = 1
    while n > 0
        digit = n % 10
        result *= digit
        n ÷= 10
    end
    result
end

function find_minimum_with_multiplicative_persistence(target_persistence)
    start_time = time()

    number = 1
    while true
        current_number = number
        current_persistence = 0

        while current_number >= 10
            current_number = digit_product(current_number)
            current_persistence += 1
        end

        if current_persistence == target_persistence
            elapsed_time = time() - start_time
            println("Time taken to find result: ", elapsed_time, " seconds")
            return number
        end

        number += 1
    end
end