C
(Điều này cuối cùng đã dài hơn dự định, nhưng dù sao tôi cũng sẽ đăng nó ...)
Vào thế kỷ 17, Wallis đã xuất bản một bộ truyện vô tận cho Pi:
(Xem
Sản phẩm vô hạn mới của Wallis- và Catalan cho các số π, e và (2 + 2) để biết thêm thông tin)
Bây giờ, để tính Pi, trước tiên chúng ta phải nhân hai để nhân ra mẫu số:
Giải pháp của tôi sau đó tính toán chuỗi vô hạn cho Pi / 2 và hai và sau đó nhân hai giá trị với nhau. Lưu ý rằng các sản phẩm vô hạn rất chậm hội tụ khi tính toán các giá trị cuối cùng.
đầu ra:
pi: 6.283182
#include "stdio.h"
#include "stdint.h"
#define ITERATIONS 10000000
#define one 1
#define IEEE_MANTISSA_MASK 0xFFFFFFFFFFFFFULL
#define IEEE_EXPONENT_POSITION 52
#define IEEE_EXPONENT_BIAS 1023
// want to get an exact as possible result, so convert
// to integers and do custom 64-bit multiplication.
double multiply(double aa, double bb)
{
// the input values will be between 1.0 and 2.0
// so drop these to less than 1.0 so as not to deal
// with the double exponents.
aa /= 2;
bb /= 2;
// extract fractional part of double, ignoring exponent and sign
uint64_t a = *(uint64_t*)&aa & IEEE_MANTISSA_MASK;
uint64_t b = *(uint64_t*)&bb & IEEE_MANTISSA_MASK;
uint64_t result = 0x0ULL;
// multiplying two 64-bit numbers is a little tricky, this is done in two parts,
// taking the upper 32 bits of each number and multiplying them, then
// then doing the same for the lower 32 bits.
uint64_t a_lsb = (a & 0xFFFFFFFFUL);
uint64_t b_lsb = (b & 0xFFFFFFFFUL);
uint64_t a_msb = ((a >> 32) & 0xFFFFFFFFUL);
uint64_t b_msb = ((b >> 32) & 0xFFFFFFFFUL);
uint64_t lsb_result = 0;
uint64_t msb_result = 0;
// very helpful link explaining how to multiply two integers
// http://stackoverflow.com/questions/4456442/interview-multiplication-of-2-integers-using-bitwise-operators
while(b_lsb != 0)
{
if (b_lsb & 01)
{
lsb_result = lsb_result + a_lsb;
}
a_lsb <<= 1;
b_lsb >>= 1;
}
while(b_msb != 0)
{
if (b_msb & 01)
{
msb_result = msb_result + a_msb;
}
a_msb <<= 1;
b_msb >>= 1;
}
// find the bit position of the most significant bit in the higher 32-bit product (msb_answer)
uint64_t x2 = msb_result;
int bit_pos = 0;
while (x2 >>= 1)
{
bit_pos++;
}
// stuff bits from the upper 32-bit product into the result, starting at bit 51 (MSB of mantissa)
int result_position = IEEE_EXPONENT_POSITION - 1;
for(;result_position > 0 && bit_pos > 0; result_position--, bit_pos--)
{
result |= ((msb_result >> bit_pos) & 0x01) << result_position;
}
// find the bit position of the most significant bit in the lower 32-bit product (lsb_answer)
x2 = lsb_result;
bit_pos = 0;
while (x2 >>= 1)
{
bit_pos++;
}
// stuff bits from the lowre 32-bit product into the result, starting at whatever position
// left off at from above.
for(;result_position > 0 && bit_pos > 0; result_position--, bit_pos--)
{
result |= ((lsb_result >> bit_pos) & 0x01) << result_position;
}
// create hex representation of the answer
uint64_t r = (uint64_t)(/* exponent */ (uint64_t)IEEE_EXPONENT_BIAS << IEEE_EXPONENT_POSITION) |
(uint64_t)( /* fraction */ (uint64_t)result & IEEE_MANTISSA_MASK);
// stuff hex into double
double d = *(double*)&r;
// since the two input values were divided by two,
// need to multiply by four to fix the result.
d *= 4;
return d;
}
int main()
{
double pi_over_two = one;
double two = one;
double num = one + one;
double dem = one;
int i=0;
i=ITERATIONS;
while(i--)
{
// pi = 2 2 4 4 6 6 8 8 ...
// 2 1 3 3 5 5 7 7 9
pi_over_two *= num / dem;
dem += one + one;
pi_over_two *= num / dem;
num += one + one;
}
num = one + one;
dem = one;
i=ITERATIONS;
while(i--)
{
// 2 = 2 4 4 6 10 12 12 14
// 1 3 5 7 9 11 13 15
two *= num / dem;
dem += one + one;
num += one + one;
two *= num / dem;
dem += one + one;
two *= num / dem;
dem += one + one;
num += one + one;
two *= num / dem;
dem += one + one;
num += one + one + one + one;
}
printf("pi: %f\n", multiply(pi_over_two, two));
return 0;
}
Số mũ trong chuyển đổi kép thực sự không thể bỏ qua. Nếu đó là thay đổi duy nhất (để lại số chia cho 2, nhân với 4, phép nhân số nguyên) thì mọi thứ sẽ hoạt động một cách đáng ngạc nhiên.