2017-12-31 124 views
1

중요 편집 : 원래 질문은 두 배와 분수의 밀도를 얻는 것이 었습니다. 복식이 아닌 복소수에 대한 답을 얻으므로 주제를 변경하여이 질문을 닫습니다. 원래의 질문의 나머지 절반은 here주어진 숫자 사이에 2 배의 밀도

새로운 질문

내가이 개 주어진 숫자 사이 두 배의 밀도를 찾으려하지만 난 좋은 방법을 생각할 수 없다. 그래서 닫힌 폼 식 doublesIn (a, b)를 찾고 있습니다. 또는 합리적인 시간에 작업을 수행하는 일부 코드.

두 배로는 가수와 지수로 수식을 사용해야합니다. 나는 이미 다음에을 사용하는 코드를 가지고 있습니다. [-1,1] (1e6 이하는 매우 느림)에 매우 느립니다.

.

아이디어가 있으십니까? 미리 감사드립니다! :)

추신 : 알고 싶다면, 저는 수학 자료를 직접 코딩하고 있습니다. 특정 알고리즘에서 두 배를 (길거나 길거나 유사한) 대체하는 것이 얼마나 유용한 지 알고 싶습니다. Gaussian 제거, newton의 뿌리 찾기 방법 등)에 대해 설명하고 있으며,이를 위해 몇 가지 조치를 원합니다.

+1

보십시오 : http://www.exploringbinary.com/the-spacing-of-decimal-floating-point-numbers/ 및 http://www.exploringbinary.com/tag/floating-point/ –

+2

직접적인 방법은 [std :: nextafter] (http://en.cppreference.com/w/cpp/numeric/math/nextafter)를 사용하는 것입니다. – Incomputable

+1

표현 가능한 모든 부동 소수점 값은 유리합니다 (무한대, NaN 등 제외). – Peter

답변

1

다음은 프로그램을 포함하여 double이 IEEE 754 64 비트 2 진 부동 소수점으로 표시된다고 가정합니다. 그럴 가능성이 가장 높지만 C++ 표준에 의해 보장되지는 않습니다.

끝에서 시작 부분을 빼고 범위가 열렸는지 닫히는지를 조정하여 일정 시간 범위 내의 부호없는 정수를 계산할 수 있기 때문에 일정 시간 범위에서 두 배를 계산할 수 있습니다.

유한 비 음수 범위의 복식은 연속적인 정수 시퀀스를 형성하는 비트 패턴을 갖습니다. 예를 들어 범위 [1.0,2.0]에는 [0x3ff0_0000_0000_0000, 0x4000_0000_0000_0000] 범위의 각 정수에 대해 하나의 double이 포함됩니다.

double 형의 유한 양수 범위는 double 형이 부정적이됨에 따라 부호없는 비트 패턴의 값이 증가한다는 점을 제외하면 같은 방식으로 동작합니다.

범위에 양수와 음수가 모두 포함되어 있으면 음수가 아닌 범위와 다른 양수가 아닌 범위를 처리 할 수 ​​있도록 범위를 0으로 분할하십시오.

대부분의 합병증은 정확한 계산을 원할 때 발생합니다. 이 경우 범위가 열렸는지 닫히는지를 조정하고 정확히 한 번만 0을 계산해야합니다.

귀하의 목적에 따라, 수십 억 개 중 하나 또는 두 개를 벗어나도 별 문제가되지 않을 수 있습니다.

다음은 아이디어를 보여주는 간단한 프로그램입니다. 오류 검사를 거의받지 못했으므로 본인 책임하에 사용하십시오.

#include <iostream> 
#include <cmath> 
using namespace std; 

uint64_t count(double start, double end); 

void testit(uint64_t expected, double start, double end) { 
    cout << hex << "Should be " << expected << ": " << count(start, end) 
      << endl; 
} 

double increment(double data, int count) { 
    int i; 
    for (i = 0; i < count; i++) { 
     data = nextafter(data, INFINITY); 
    } 
    return data; 
} 

double decrement(double data, int count) { 
    int i; 
    for (i = 0; i < count; i++) { 
     data = nextafter(data, -INFINITY); 
    } 
    return data; 
} 

int main() { 
    testit((uint64_t) 1 << 52, 1.0, 2.0); 
    testit(5, 3.0, increment(3.0, 5)); 
    testit(2, decrement(0, 1), increment(0, 1)); 
    testit((uint64_t) 1 << 52, -2.0, -1.0); 
    testit(1, -0.0, increment(0, 1)); 
    testit(10, decrement(0,10), -0.0); 
    return 0; 
} 

// Return the bit pattern representing a double as 
// a 64-bit unsigned integer. 
uint64_t toInteger(double data) { 
    return *reinterpret_cast<uint64_t *>(&data); 
} 

// Count the doubles in a range, assuming double 
// is IEEE 754 64-bit binary. 
// Counts [start,end), including start but excluding end 
uint64_t count(double start, double end) { 
    if (!(isfinite(start) && isfinite(end) && start <= end)) { 
     // Insert real error handling here 
     cerr << "error" << endl; 
     return 0; 
    } 
    if (start < 0) { 
     if (end < 0) { 
      return count(fabs(end), fabs(start)); 
     } else if (end == 0) { 
      return count(0, fabs(start)); 
     } else { 
      return count(start, 0) + count(0, end); 
     } 
    } 
    if (start == -0.0) { 
     start = 0.0; 
    } 
    return toInteger(end) - toInteger(start); 
} 
+0

답해 주셔서 감사합니다. 당신이 말했듯이, 나는 범위 내에서 복소수와 분수의 정확한 양을 필요로하지 않으며, 비교할 수있는 좋은 근사값 만이 더 많은 수를 나타낼 수 있습니다. 범위는 또한 (2,3)과 (-3, -2) 사이의 밀도가 동일하므로 음수가 될 수 없습니다. 그러나이 정보로 어떻게 닫힌 형식 표현을 얻을 수 있는지 알지 못합니다. 그리고 선형의 경우에도 각 하나의 계산이 약간 느리다고 생각합니다. 가장 작은 양의 정수 사이에 많은 수의 표현 가능한 숫자가 있기 때문입니다. – Pernoctador

+0

@Pernoctador 범위 내 정수의 개수를 생각해보십시오. 'unsigned long L = * (unsigned long *) & d;'의 결과에 적용하면'd'는 double입니다. –

+0

굉장! 나는 시험을했고 나는 잘못된 것을 발견하지 못했습니다. 정말 고맙습니다. 이제 분수에 적합한 코드 또는 수학 표현식을 가져와야합니다. – Pernoctador