do
(W końcu było to dłuższe niż zamierzone, ale i tak opublikuję ...)
W XVII wieku Wallis opublikował nieskończoną serię dla Pi:
(Więcej informacji na temat π, e i √ (2 + √2), aby uzyskać więcej informacji, patrz
Nowe nieskończone produkty typu Wallis i katalońskiego )
Teraz, aby obliczyć Pi, musimy najpierw pomnożyć przez dwa, aby wyliczyć mianownik:
Moje rozwiązanie oblicza następnie szereg nieskończony dla Pi / 2 i dwóch, a następnie mnoży te dwie wartości razem. Zauważ, że nieskończone produkty są niezwykle powolne w zbieraniu się podczas obliczania ostatecznych wartości.
wydajność:
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;
}
Wykładnika podwójnej konwersji nie można tak naprawdę zignorować. Jeśli to jedyna zmiana (zostaw dzielenie przez 2, pomnóż przez 4, mnożenie przez liczby całkowite), wszystko zaskakująco działa.