기음
(이것은 의도 된 것보다 길어졌지만 어쨌든 게시 할 것입니다 ...)
17 세기에 Wallis는 Pi에 대한 무한 시리즈를 발표했습니다.
( π, e 및 √ (2 + √2에 대한 새로운 월리스 및 카탈로니아 어 유형 무한 제품 참조
) 참조)
이제 Pi를 계산하려면 먼저 분모를 빼기 위해 2를 곱해야합니다.
내 솔루션은 Pi / 2 및 2에 대한 무한 계열을 계산 한 다음 두 값을 곱합니다. 최종 값을 계산할 때 무한 제품의 수렴 속도가 매우 느립니다.
산출:
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;
}
이중 변환의 지수는 실제로 무시할 수 없습니다. 그것이 유일한 변화라면 (나눗셈을 2로 나누고, 4를 곱하고, 정수 곱셈을 남기십시오) 모든 것이 놀랍게 작동합니다.