2014-09-16 3 views
0

Я просто изучаю ржавчину, отныне у этого вопроса есть, вероятно, какой-то тривиальный ответ.Доступ к отдельным цифрам BigUint в ржавчине

Я хочу получить доступ к отдельным цифрам ржавчины BigUint. Это для проекта Эйлера головоломка, запрашивающая сумму этих цифр.

Я сделал это, как показано ниже:

let mut f = func(100); 
let mut total: BigUint = Zero::zero(); 
while f > FromPrimitive::from_uint(0).unwrap() { 
    let digit = f % FromPrimitive::from_uint(10).unwrap(); 
    f = f/FromPrimitive::from_uint(10).unwrap(); 
    total = total + digit; 
} 
println!(""); 
println!("Sum of digits of func(100) = {}", total); 

Это работает, но это довольно сложно, потому что я считаю, что эти цифры internaly хранятся в виде массива, но я не могу получить доступ к ним непосредственно, поскольку основным данным член закрыт.

Есть ли способ сделать это более простым способом?

+0

Я недавно сделал это, выполнив кастинг на String и итерируя эти цифры. –

+0

@ C.Quilley: Это может быть правильный путь. Мне интересно, являются ли внутренние BigDigits фактически базовыми 10. Если не вывод строки, это, конечно, путь. Не могли бы вы дать ответ? – kriss

+0

обычно я был бы рад, но я на работе, и у меня нет источника. –

ответ

0

Я закончил делать это с помощью to_string() как это было предложено @ C.Quilley. Но поскольку @Levans указал, что внутренняя реализация просто выполняет div_rem. Я по-прежнему предпочитаю эту версию, потому что я считаю ее более читаемой и простой.

extern crate num; 
use num::bigint::BigUint; 

// What this function does is irrelevant 
fn func(n: uint) -> BigUint { 
    let p : BigUint = FromPrimitive::from_uint(n).unwrap(); 
    p*p*p*p*p*p*p*p*p*p*p*p*p 
} 

fn main() { 
    let n = 2014u; 
    let f = func(n); 
    let total: uint = f.to_string().as_slice().chars() 
     .fold(0, |a, b| a + b as uint - '0' as uint); 
    println!("Sum of digits of func({}) = {} : {}", n, f, total); 
} 
1

Внутренняя память BigUint является вектором BigDigit, который является псевдонимом для u32, поэтому, вероятно, вам не поможет получить сумму базовых 10 цифр.

Сомневаюсь отливка String бы эффективный способ вычислить это, но вы можете сделать его немного более простым, используя метод div_rem() от признака Integer. (В конце концов, литье в String делает это вычисление внутренне.)

extern crate num; 

use std::num::Zero; 
use num::bigint::BigUint; 
use num::integer::Integer; 

fn main() { 
    let mut f = func(100); 
    let mut total: BigUint = Zero::zero(); 
    let ten: BigUint = FromPrimitive::from_uint(10).unwrap(); 
    while f > Zero::zero() { 
     let (quotient, remainder) = f.div_rem(&ten); 
     f = quotient; 
     total = total + remainder; 
    } 
    println!(""); 
    println!("Sum of digits of func(100) = {}", total); 
} 
+0

Если кастинг для String на самом деле делает это вместо использования какого-то специализированного алгоритма, то это действительно не лучше. Если я правильно понимаю, как div_rem в лучшем случае O (n), эти реализации будут O (n ** 2). Я ожидал чего-то лучшего от внутреннего преобразования в строку. – kriss

+0

Ну, если у вас есть число, хранящееся в базе, которая не '10', а она нужна в базе' 10', у вас нет выбора, кроме как преобразовать ее, и это алгоритм для этого. Проверьте сам вариант 'BigUint'' Show', он делает это также здесь: http://doc.rust-lang.org/src/num/home/rustbuild/src/rust-buildbot/slave/nightly-linux /build/src/libnum/bigint.rs.html#665-678 – Levans

+0

Это может быть фактическая реализация (выглядит действительно так в bigint.rs, но не уверен, я еще не читаю код ржавчины). Если так, то это наивная, которая может быть улучшена когда-нибудь. Конечно, вы можете сделать это так, но почему это лучший алгоритм? Я ожидал бы, что алгоритм разделения и покорения будет намного лучше. Возможно, используя некоторые промежуточные шаги, разделяющие некоторую мощность базы, чтобы разделить число в двух частях примерно такого же размера и рекурсивно сделать это http://stackoverflow.com/questions/6493279/how-can-i-convert-a-very- – kriss

Смежные вопросы