|
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