shootout-pidigits.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // The Computer Language Benchmarks Game
  2. // http://benchmarksgame.alioth.debian.org/
  3. //
  4. // contributed by the Rust Project Developers
  5. // Copyright (c) 2013-2014 The Rust Project Developers
  6. //
  7. // All rights reserved.
  8. //
  9. // Redistribution and use in source and binary forms, with or without
  10. // modification, are permitted provided that the following conditions
  11. // are met:
  12. //
  13. // - Redistributions of source code must retain the above copyright
  14. // notice, this list of conditions and the following disclaimer.
  15. //
  16. // - Redistributions in binary form must reproduce the above copyright
  17. // notice, this list of conditions and the following disclaimer in
  18. // the documentation and/or other materials provided with the
  19. // distribution.
  20. //
  21. // - Neither the name of "The Computer Language Benchmarks Game" nor
  22. // the name of "The Computer Language Shootout Benchmarks" nor the
  23. // names of its contributors may be used to endorse or promote
  24. // products derived from this software without specific prior
  25. // written permission.
  26. //
  27. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  30. // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  31. // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  32. // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  33. // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  34. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  36. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  37. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  38. // OF THE POSSIBILITY OF SUCH DAMAGE.
  39. extern crate num;
  40. use std::str::FromStr;
  41. use std::io;
  42. use num::traits::{FromPrimitive, ToPrimitive};
  43. use num::{BigInt, Integer, One, Zero};
  44. struct Context {
  45. numer: BigInt,
  46. accum: BigInt,
  47. denom: BigInt,
  48. }
  49. impl Context {
  50. fn new() -> Context {
  51. Context {
  52. numer: One::one(),
  53. accum: Zero::zero(),
  54. denom: One::one(),
  55. }
  56. }
  57. fn from_i32(i: i32) -> BigInt {
  58. FromPrimitive::from_i32(i).unwrap()
  59. }
  60. fn extract_digit(&self) -> i32 {
  61. if self.numer > self.accum {return -1;}
  62. let (q, r) =
  63. (&self.numer * Context::from_i32(3) + &self.accum)
  64. .div_rem(&self.denom);
  65. if r + &self.numer >= self.denom {return -1;}
  66. q.to_i32().unwrap()
  67. }
  68. fn next_term(&mut self, k: i32) {
  69. let y2 = Context::from_i32(k * 2 + 1);
  70. self.accum = (&self.accum + (&self.numer << 1)) * &y2;
  71. self.numer = &self.numer * Context::from_i32(k);
  72. self.denom = &self.denom * y2;
  73. }
  74. fn eliminate_digit(&mut self, d: i32) {
  75. let d = Context::from_i32(d);
  76. let ten = Context::from_i32(10);
  77. self.accum = (&self.accum - &self.denom * d) * &ten;
  78. self.numer = &self.numer * ten;
  79. }
  80. }
  81. fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> {
  82. let mut k = 0;
  83. let mut context = Context::new();
  84. for i in 1..(n+1) {
  85. let mut d;
  86. loop {
  87. k += 1;
  88. context.next_term(k);
  89. d = context.extract_digit();
  90. if d != -1 {break;}
  91. }
  92. try!(write!(out, "{}", d));
  93. if i % 10 == 0 { try!(write!(out, "\t:{}\n", i)); }
  94. context.eliminate_digit(d);
  95. }
  96. let m = n % 10;
  97. if m != 0 {
  98. for _ in m..10 { try!(write!(out, " ")); }
  99. try!(write!(out, "\t:{}\n", n));
  100. }
  101. Ok(())
  102. }
  103. const DEFAULT_DIGITS: isize = 512;
  104. fn main() {
  105. let args = std::env::args().collect::<Vec<_>>();
  106. let n = if args.len() < 2 {
  107. DEFAULT_DIGITS
  108. } else if args[1] == "--bench" {
  109. return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap()
  110. } else {
  111. FromStr::from_str(&args[1]).unwrap()
  112. };
  113. pidigits(n, &mut std::io::stdout()).unwrap();
  114. }