|
1 | | -// xfail-test |
| 1 | +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT |
| 2 | +// file at the top-level directory of this distribution and at |
| 3 | +// http://rust-lang.org/COPYRIGHT. |
| 4 | +// |
| 5 | +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 6 | +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 7 | +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| 8 | +// option. This file may not be copied, modified, or distributed |
| 9 | +// except according to those terms. |
| 10 | + |
| 11 | +extern mod extra; |
2 | 12 |
|
3 | | -use std::cast::transmute; |
4 | 13 | use std::from_str::FromStr; |
5 | | -use std::libc::{STDOUT_FILENO, c_char, c_int, c_uint, c_void, fdopen, fputc}; |
6 | | -use std::libc::{fputs}; |
7 | | -use std::ptr::null; |
8 | | - |
9 | | -struct mpz_t { |
10 | | - _mp_alloc: c_int, |
11 | | - _mp_size: c_int, |
12 | | - _mp_limb_t: *c_void, |
13 | | -} |
14 | | - |
15 | | -impl mpz_t { |
16 | | - fn new() -> mpz_t { |
17 | | - mpz_t { |
18 | | - _mp_alloc: 0, |
19 | | - _mp_size: 0, |
20 | | - _mp_limb_t: null(), |
21 | | - } |
22 | | - } |
23 | | -} |
24 | | - |
25 | | -#[link_args="-lgmp"] |
26 | | -extern { |
27 | | - #[link_name="__gmpz_add"] |
28 | | - fn mpz_add(x: *mpz_t, y: *mpz_t, z: *mpz_t); |
29 | | - #[link_name="__gmpz_cmp"] |
30 | | - fn mpz_cmp(x: *mpz_t, y: *mpz_t) -> c_int; |
31 | | - #[link_name="__gmpz_fdiv_qr"] |
32 | | - fn mpz_fdiv_qr(a: *mpz_t, b: *mpz_t, c: *mpz_t, d: *mpz_t); |
33 | | - #[link_name="__gmpz_get_ui"] |
34 | | - fn mpz_get_ui(x: *mpz_t) -> c_uint; |
35 | | - #[link_name="__gmpz_init"] |
36 | | - fn mpz_init(x: *mpz_t); |
37 | | - #[link_name="__gmpz_init_set_ui"] |
38 | | - fn mpz_init_set_ui(x: *mpz_t, y: c_uint); |
39 | | - #[link_name="__gmpz_mul_2exp"] |
40 | | - fn mpz_mul_2exp(x: *mpz_t, y: *mpz_t, z: c_uint); |
41 | | - #[link_name="__gmpz_mul_ui"] |
42 | | - fn mpz_mul_ui(x: *mpz_t, y: *mpz_t, z: c_uint); |
43 | | - #[link_name="__gmpz_submul_ui"] |
44 | | - fn mpz_submul_ui(x: *mpz_t, y: *mpz_t, z: c_uint); |
45 | | -} |
| 14 | +use std::num::One; |
| 15 | +use std::num::Zero; |
| 16 | +use std::num::FromPrimitive; |
| 17 | +use extra::bigint::BigInt; |
46 | 18 |
|
47 | 19 | struct Context { |
48 | | - numer: mpz_t, |
49 | | - accum: mpz_t, |
50 | | - denom: mpz_t, |
51 | | - tmp1: mpz_t, |
52 | | - tmp2: mpz_t, |
| 20 | + numer: BigInt, |
| 21 | + accum: BigInt, |
| 22 | + denom: BigInt, |
53 | 23 | } |
54 | 24 |
|
55 | 25 | impl Context { |
56 | 26 | fn new() -> Context { |
57 | | - unsafe { |
58 | | - let mut result = Context { |
59 | | - numer: mpz_t::new(), |
60 | | - accum: mpz_t::new(), |
61 | | - denom: mpz_t::new(), |
62 | | - tmp1: mpz_t::new(), |
63 | | - tmp2: mpz_t::new(), |
64 | | - }; |
65 | | - mpz_init(&result.tmp1); |
66 | | - mpz_init(&result.tmp2); |
67 | | - mpz_init_set_ui(&result.numer, 1); |
68 | | - mpz_init_set_ui(&result.accum, 0); |
69 | | - mpz_init_set_ui(&result.denom, 1); |
70 | | - result |
| 27 | + Context { |
| 28 | + numer: One::one(), |
| 29 | + accum: Zero::zero(), |
| 30 | + denom: One::one(), |
71 | 31 | } |
72 | 32 | } |
73 | 33 |
|
74 | | - fn extract_digit(&mut self) -> i32 { |
75 | | - unsafe { |
76 | | - if mpz_cmp(&self.numer, &self.accum) > 0 { |
77 | | - return -1; |
78 | | - } |
79 | | - |
80 | | - // Compute (numer * 3 + accum) / denom |
81 | | - mpz_mul_2exp(&self.tmp1, &self.numer, 1); |
82 | | - mpz_add(&self.tmp1, &self.tmp1, &self.numer); |
83 | | - mpz_add(&self.tmp1, &self.tmp1, &self.accum); |
84 | | - mpz_fdiv_qr(&self.tmp1, &self.tmp2, &self.tmp1, &self.denom); |
85 | | - |
86 | | - // Now, if (numer * 4 + accum) % denom... |
87 | | - mpz_add(&self.tmp2, &self.tmp2, &self.numer); |
88 | | - |
89 | | - // ... is normalized, then the two divisions have the same result. |
90 | | - if mpz_cmp(&self.tmp2, &self.denom) >= 0 { |
91 | | - return -1; |
92 | | - } |
93 | | - |
94 | | - mpz_get_ui(&self.tmp1) as i32 |
95 | | - } |
| 34 | + fn from_int(i: int) -> BigInt { |
| 35 | + FromPrimitive::from_int(i).unwrap() |
96 | 36 | } |
97 | 37 |
|
98 | | - fn next_term(&mut self, k: u32) { |
99 | | - unsafe { |
100 | | - let y2 = k*2 + 1; |
| 38 | + fn extract_digit(&self) -> int { |
| 39 | + if self.numer > self.accum {return -1;} |
| 40 | + let (q, r) = |
| 41 | + (self.numer * Context::from_int(3) + self.accum) |
| 42 | + .div_rem(&self.denom); |
| 43 | + if r + self.numer >= self.denom {return -1;} |
| 44 | + q.to_int().unwrap() |
| 45 | + } |
101 | 46 |
|
102 | | - mpz_mul_2exp(&self.tmp1, &self.numer, 1); |
103 | | - mpz_add(&self.accum, &self.accum, &self.tmp1); |
104 | | - mpz_mul_ui(&self.accum, &self.accum, y2); |
105 | | - mpz_mul_ui(&self.numer, &self.numer, k); |
106 | | - mpz_mul_ui(&self.denom, &self.denom, y2); |
107 | | - } |
| 47 | + fn next_term(&mut self, k: int) { |
| 48 | + let y2 = Context::from_int(k * 2 + 1); |
| 49 | + self.accum = (self.accum + (self.numer << 1)) * y2; |
| 50 | + self.numer = self.numer * Context::from_int(k); |
| 51 | + self.denom = self.denom * y2; |
108 | 52 | } |
109 | 53 |
|
110 | | - fn eliminate_digit(&mut self, d: u32) { |
111 | | - unsafe { |
112 | | - mpz_submul_ui(&self.accum, &self.denom, d); |
113 | | - mpz_mul_ui(&self.accum, &self.accum, 10); |
114 | | - mpz_mul_ui(&self.numer, &self.numer, 10); |
115 | | - } |
| 54 | + fn eliminate_digit(&mut self, d: int) { |
| 55 | + let d = Context::from_int(d); |
| 56 | + let ten = Context::from_int(10); |
| 57 | + self.accum = (self.accum - self.denom * d) * ten; |
| 58 | + self.numer = self.numer * ten; |
116 | 59 | } |
117 | 60 | } |
118 | 61 |
|
119 | | -fn pidigits(n: u32) { |
120 | | - unsafe { |
121 | | - let mode = "w"; |
122 | | - let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0])); |
| 62 | +fn pidigits(n: int) { |
| 63 | + let mut k = 0; |
| 64 | + let mut context = Context::new(); |
123 | 65 |
|
124 | | - let mut d: i32; |
125 | | - let mut i: u32 = 0, k: u32 = 0, m: u32; |
126 | | - |
127 | | - let mut context = Context::new(); |
| 66 | + for i in range(1, n + 1) { |
| 67 | + let mut d; |
128 | 68 | loop { |
129 | | - loop { |
130 | | - k += 1; |
131 | | - context.next_term(k); |
132 | | - d = context.extract_digit(); |
133 | | - if d != -1 { |
134 | | - break; |
135 | | - } |
136 | | - } |
| 69 | + k += 1; |
| 70 | + context.next_term(k); |
| 71 | + d = context.extract_digit(); |
| 72 | + if d != -1 {break;} |
| 73 | + } |
137 | 74 |
|
138 | | - fputc((d as c_int) + ('0' as c_int), stdout); |
| 75 | + print!("{}", d); |
| 76 | + if i % 10 == 0 {print!("\t:{}\n", i);} |
139 | 77 |
|
140 | | - i += 1; |
141 | | - m = i % 10; |
142 | | - if m == 0 { |
143 | | - let res = fmt!("\t:%d\n", i as int); |
144 | | - fputs(transmute(&res[0]), stdout); |
145 | | - } |
146 | | - if i >= n { |
147 | | - break; |
148 | | - } |
149 | | - context.eliminate_digit(d as u32); |
150 | | - } |
| 78 | + context.eliminate_digit(d); |
| 79 | + } |
151 | 80 |
|
152 | | - if m != 0 { |
153 | | - m = 10 - m; |
154 | | - while m != 0 { |
155 | | - m -= 1; |
156 | | - fputc(' ' as c_int, stdout); |
157 | | - } |
158 | | - let res = fmt!("\t:%d\n", i as int); |
159 | | - fputs(transmute(&res[0]), stdout); |
160 | | - } |
| 81 | + let m = n % 10; |
| 82 | + if m != 0 { |
| 83 | + for _ in range(m, 10) {print(" ");} |
| 84 | + print!("\t:{}\n", n); |
161 | 85 | } |
162 | 86 | } |
163 | 87 |
|
164 | 88 | fn main() { |
165 | | - let n: u32 = FromStr::from_str(os::args()[1]).get(); |
| 89 | + let args = std::os::args(); |
| 90 | + let n = if args.len() < 2 { |
| 91 | + 512 |
| 92 | + } else { |
| 93 | + FromStr::from_str(args[1]).unwrap() |
| 94 | + }; |
166 | 95 | pidigits(n); |
167 | 96 | } |
0 commit comments