2015-08-31 9 views
5

मैं एक पाप क्योंकि बनाना चाहते हैं अप, अनुकूलन के लिए टेबल देखने के लिए 0 से UCHAR_MAX को एक सरणी सूचकांक का उपयोग करके ताकि 0 रेडियन सूचकांक 0 है, pi/2 रेडियन UCHAR_MAX/4 है:रेडियन बड़ा होने पर यह पाप क्यों गलत दिखता है?

sincos.h

#include <limits.h> 
#include <math.h> 
int sini[UCHAR_MAX]; 
int cosi[UCHAR_MAX]; 
#define MAGNIFICATION 256 
#define SIN(i) sini[i]/MAGNIFICATION 
#define COS(i) cosi[i]/MAGNIFICATION 

void initTable(){ 
    for(int i=0;i<UCHAR_MAX;i++){ 
     sini[i]=sinf(i*2*M_PI/UCHAR_MAX)*MAGNIFICATION; 
     cosi[i]=cosf(i*2*M_PI/UCHAR_MAX)*MAGNIFICATION; 
    } 
} 

UCHAR_MAX का उपयोग कर के रूप में अधिकतम मैं रेडियन thats 0 से करने के लिए 2*pi केवल भिन्न होता है simulates को अहस्ताक्षरित चार अतिप्रवाह का अच्छा इस्तेमाल करना चाहते हैं के कारण: उदाहरण के लिए, अगर रेडियन का मूल्य 2*pi है, सरणी के सूचकांक UCHAR_MAX हो जाता है , क्योंकि यह अतिप्रवाह है, यह स्वचालित है ly 0 हो जाता है और कोई मॉड आवश्यक नहीं है (यदि मैं 0 से 360 डोमेन के रूप में उपयोग करता हूं तो मुझे हर बार index%360 की गणना करने की आवश्यकता हो सकती है)। जैसे निम्नलिखित

float rad[]={2.0f,4.0f,6.0f,8.0f,10.0f,-2.0f,-4.0f,-6.0f,-8.0f,-10.0f}; 

: तो मैं कुछ रेडियन मूल्यों के साथ यह परीक्षण

#include "sincos.h" 
#include <stdio.h> 
int main(){ 
    initTable(); 
    unsigned char radToIndex; 
    float rad[]={2.0f,4.0f,6.0f,8.0f,10.0f,-2.0f,-4.0f,-6.0f,-8.0f,-10.0f}; 
    int scalar=123; 
    printf("scalar=%d\n",scalar); 
    for(int i=0;i<sizeof(rad)/sizeof(float);i++){ 
     radToIndex=rad[i]*UCHAR_MAX/2/M_PI; 
     printf("%d*sin(%f) : %f , %d\n",scalar,rad[i],scalar*sinf(rad[i]),scalar*SIN(radToIndex)); 
    } 
    return 0; 
} 

मैं 123*sin(radian) साथ तालिका का परीक्षण, परिणाम मिले शुरू होता है वास्तविक एक से परे जाना जब रेडियन बढ़ जाती है की भयावहता (

scalar=123 
123*sin(2.000000) : 111.843582 , 111 
123*sin(4.000000) : -93.086708 , -92 
123*sin(6.000000) : -34.368107 , -35 
123*sin(8.000000) : 121.691063 , 122 
123*sin(10.000000) : -66.914597 , -61 
123*sin(-2.000000) : -111.843582 , -112 
123*sin(-4.000000) : 93.086708 , 90 
123*sin(-6.000000) : 34.368107 , 38 
123*sin(-8.000000) : -121.691063 , -122 
123*sin(-10.000000) : 66.914597 , 59 

और एक अन्य डेटा के साथ परीक्षण:

जब रेडियन 10 या -10) है
float rad[]={0.01f,0.1f,1.0f,10.0f,100.0f,1000.0f,-0.01f,-0.1f,-1.0f,-10.0f,-100.0f,-1000.0f}; 

उत्पादन:

scalar=123 
123*sin(0.010000) : 1.229980 , 0 
123*sin(0.100000) : 12.279510 , 12 
123*sin(1.000000) : 103.500931 , 102 
123*sin(10.000000) : -66.914597 , -61 
123*sin(100.000000) : -62.282974 , -97 
123*sin(1000.000000) : 101.706184 , -25 
123*sin(-0.010000) : -1.229980 , 0 
123*sin(-0.100000) : -12.279510 , -8 
123*sin(-1.000000) : -103.500931 , -100 
123*sin(-10.000000) : 66.914597 , 59 
123*sin(-100.000000) : 62.282974 , 98 
123*sin(-1000.000000) : -101.706184 , 22 

त्रुटि वृद्धि जब परिमाण बढ़ जाती है, इसलिए मैं काफी यकीन है कि तालिका गलत हो जाता है जब रेडियन बड़ी है कर रहा हूँ। sincos.h में सटीकता को नियंत्रित करने के एक मूल्य आवर्धन है, मैं इसे 256 से 4096 करने के लिए बदल गया है, लेकिन यह कोई बहुत सुधार लगता है:

scalar=123 
123*sin(0.010000) : 1.229980 , 0 
123*sin(0.100000) : 12.279510 , 12 
123*sin(1.000000) : 103.500931 , 102 
123*sin(10.000000) : -66.914597 , -62 
123*sin(100.000000) : -62.282974 , -97 
123*sin(1000.000000) : 101.706184 , -25 
123*sin(-0.010000) : -1.229980 , 0 
123*sin(-0.100000) : -12.279510 , -9 
123*sin(-1.000000) : -103.500931 , -100 
123*sin(-10.000000) : 66.914597 , 59 
123*sin(-100.000000) : 62.282974 , 99 
123*sin(-1000.000000) : -101.706184 , 22 

क्यों कि होगा? क्या टेबल की तार्किक त्रुटि है?

+0

आप सटीकता कैसे messure के लिए? – Zich

उत्तर

5

[संपादित करें]

कोण अतीत बढ़ने के साथ कोड अनुभवों समस्याओं ओपी के निम्नलिखित कोड में गलत "सापेक्ष" अंकगणित की वजह से 360 डिग्री। उत्पाद rad[i]*UCHAR_MAX/2/M_PI को एक (8-बिट) unsigned char में परिवर्तित किया गया है जो एक मॉड्यूलो 256 है, फिर भी कोड UCHAR_MAX (255) द्वारा तालिकाओं और कोड स्केल कर रहा है। इस उत्तर के अंतिम बिंदु विवरण इस के पहलुओं, अभी तक यह स्पष्ट है कि टेबल और कोड उपयोग 256, नहीं होना चाहिए 255.

unsigned char radToIndex; 
radToIndex=rad[i]*UCHAR_MAX/2/M_PI; // wrong scaling 
radToIndex=rad[i]*(UCHAR_MAX+1)/2/M_PI; // right 
इसके अलावा

, ध्यान दें ओपी के कोड व्यवहार अपरिभाषित है जब radToIndex == UCHAR_MAX कि के रूप में गलत सूचकांक है int sini[UCHAR_MAX]; पर।

ऊपर फिक्स और 3 फिक्स नीचे का उपयोग करना:

123*sin(2.000000) : 111.843584 , 112 
123*sin(4.000000) : -93.086707 , -93 
123*sin(6.000000) : -34.368106 , -35 
123*sin(8.000000) : 121.691064 , 121 
123*sin(10.000000) : -66.914597 , -65 
123*sin(-2.000000) : -111.843584 , -112 
123*sin(-4.000000) : 93.086707 , 93 
123*sin(-6.000000) : 34.368106 , 35 
123*sin(-8.000000) : -121.691064 , -121 
123*sin(-10.000000) : 66.914597 , 65 

कोड भी double rounding या अधिक सामना कर रहा है: तालिका आकार 256, गोल सूचकांक, ज्या का मूल्य दौर, में तालिका बनाने परिणामों के लिए डबल का उपयोग बहुमूल्य: डबल छंटनी।

radToIndex=rad[i]*UCHAR_MAX/2/M_PI; 0 की ओर truncates। तो सूचकांक छोटे, निकटतम नहीं बनाया गया है।

तालिका निर्माण sini[i]=sinf(i*2*M_PI/UCHAR_MAX)*MAGNIFICATION; भी 0 की ओर छंटनी करता है। इसलिए sini[] को छोटा बनाया गया है, निकटतम int नहीं है।

सुधारने के लिए, बस round() के साथ निकटतम में जाएं।

sini[i] = (int) roundf(sinf(i*2*M_PI/UCHAR_MAX)*MAGNIFICATION); 
radToIndex= (int) round(rad[i]*UCHAR_MAX/2/M_PI); 

एक सामान्य टिप्पणी के रूप में, float के बाद आम तौर पर 24 बिट परिशुद्धता और int संभावना 31 +, पर हस्ताक्षर अतिरिक्त सुधार के लिए तालिका बनाने के लिए double का उपयोग करें।

sini[i] = (int) round(sin(i*2.0*M_PI/UCHAR_MAX)*MAGNIFICATION); 

इसके अलावा, BAM देखें UCHAR_MAX + 1 उपयोग करने की अनुशंसा:

बंद से 1.

सरणी के सूचकांक UCHAR_MAX हो जाता है, क्योंकि overflows, यह स्वतः ही 0

हो जाता है

UCHAR_MAX अतिप्रवाह नहीं है, UCHAR_MAX + 1 अतिप्रवाह और हो जाता है 0. (unsigned char गणित)

int sini[UCHAR_MAX+1]; 
for (int i=0; i<(UCHAR_MAX+1); i++) { 
    // Rather than `i*2*M_PI/UCHAR_MAX`, use 
    sini[i]=sinf(i*2*M_PI/(UCHAR_MAX + 1))*MAGNIFICATION; 
+0

तालिका निर्माण में 'डबल' और 'पाप() 'का उपयोग करके' मैग्निफिकेशन> 1e23' उपयोगी होता है। – chux

0

समस्या का स्रोत

ऐसा लगता है कि आप के लिए चल बिन्दु संख्या की गोलाई और चल बिन्दु क्रमांक देने से त्रुटियों हो रही है एक unsigned char

आपके पोस्ट कोड से अनुकूलित निम्न प्रोग्राम, यह दर्शाता है कि फ़्लोटिंग पॉइंट नंबर के चारों ओर भी इंडेक्स विचलन शुरू होता है। उपरोक्त कार्यक्रम के

#include <limits.h> 
#include <math.h> 

int sini[UCHAR_MAX]; 
int cosi[UCHAR_MAX]; 
double angle[UCHAR_MAX]; 


#define MAGNIFICATION 256 
#define SIN(i) sini[i]/MAGNIFICATION 
#define COS(i) cosi[i]/MAGNIFICATION 

void initTable() 
{ 
    double M_PI = 4.0*atan(1.0); 
    for(int i=0;i<UCHAR_MAX;i++) 
    { 
     angle[i] = i*2*M_PI/UCHAR_MAX; 
     sini[i]=sinf(angle[i])*MAGNIFICATION; 
     cosi[i]=cosf(angle[i])*MAGNIFICATION; 
    } 
} 

#include <stdio.h> 

void test3() 
{ 
    int radToIndexInt; 
    unsigned char radToIndexChar; 
    float radTemp; 
    float rad[]={2.0f,4.0f,6.0f,8.0f,10.0f,-2.0f,-4.0f,-6.0f,-8.0f,-10.0f}; 
    double M_PI = 4.0*atan(1.0); 

    for(int i=0;i<sizeof(rad)/sizeof(float);i++) 
    { 
     radTemp = rad[i]*UCHAR_MAX/2/M_PI; 
     radToIndexInt = round(radTemp); 
     radToIndexInt %= UCHAR_MAX; 
     if (radToIndexInt < 0) 
     { 
     radToIndexInt += UCHAR_MAX; 
     } 

     radToIndexChar = round(radTemp); 

     printf("radToIndexInt: %d, radToIndexChar: %d\n", 
      radToIndexInt, radToIndexChar); 

    } 
} 

int main() 
{ 
    initTable(); 

    test3(); 

    return 0; 
} 

आउटपुट:

:

radToIndexInt: 81, radToIndexChar: 81 
radToIndexInt: 162, radToIndexChar: 162 
radToIndexInt: 244, radToIndexChar: 244 
radToIndexInt: 70, radToIndexChar: 69 
radToIndexInt: 151, radToIndexChar: 150 
radToIndexInt: 174, radToIndexChar: 175 
radToIndexInt: 93, radToIndexChar: 94 
radToIndexInt: 11, radToIndexChar: 12 
radToIndexInt: 185, radToIndexChar: 187 
radToIndexInt: 104, radToIndexChar: 106 

समाधान

radToIndex=round(radTemp); 
    radToIndex %= UCHAR_MAX; 
    if (radToIndex < 0) 
    { 
    radToIndex += UCHAR_MAX; 
    } 

का उपयोग कर सूचकांक की गणना करने से, मैं बहुत करीब जवाब पाने

यहां एक प्रोग्राम है, जिसे एक बार फिर से आपके पोस्ट कोड से अनुकूलित किया गया है, दर्शाता है कि उपरोक्त तर्क कार्यों का उपयोग करना।

#include <limits.h> 
#include <math.h> 

int sini[UCHAR_MAX]; 
int cosi[UCHAR_MAX]; 
double angle[UCHAR_MAX]; 


#define MAGNIFICATION 256 
#define SIN(i) sini[i]/MAGNIFICATION 
#define COS(i) cosi[i]/MAGNIFICATION 

void initTable() 
{ 
    double M_PI = 4.0*atan(1.0); 
    for(int i=0;i<UCHAR_MAX;i++) 
    { 
     angle[i] = i*2*M_PI/UCHAR_MAX; 
     sini[i]=sinf(angle[i])*MAGNIFICATION; 
     cosi[i]=cosf(angle[i])*MAGNIFICATION; 
    } 
} 

#include <stdio.h> 

void test2() 
{ 
    int radToIndex; 
    float radTemp; 
    int scalar=123; 
    float rad[]={0.01f,0.1f,1.0f,10.0f,100.0f,1000.0f,-0.01f,-0.1f,-1.0f,-10.0f,-100.0f,-1000.0f}; 
    double M_PI = 4.0*atan(1.0); 

    printf("scalar=%d\n",scalar); 
    for(int i=0;i<sizeof(rad)/sizeof(float);i++) 
    { 
     radTemp = rad[i]*UCHAR_MAX/2/M_PI; 
     radToIndex=round(radTemp); 
     radToIndex %= UCHAR_MAX; 
     if (radToIndex < 0) 
     { 
     radToIndex += UCHAR_MAX; 
     } 
     printf("%d*sin(%f) : %f , %d\n", 
      scalar,rad[i],scalar*sinf(rad[i]),scalar*SIN(radToIndex)); 

    } 
} 

void test1() 
{ 
    int radToIndex; 
    float radTemp; 
    int scalar=123; 
    float rad[]={2.0f,4.0f,6.0f,8.0f,10.0f,-2.0f,-4.0f,-6.0f,-8.0f,-10.0f}; 
    double M_PI = 4.0*atan(1.0); 

    printf("scalar=%d\n",scalar); 
    for(int i=0;i<sizeof(rad)/sizeof(float);i++) 
    { 
     radTemp = rad[i]*UCHAR_MAX/2/M_PI; 
     radToIndex=round(radTemp); 
     radToIndex %= UCHAR_MAX; 
     if (radToIndex < 0) 
     { 
     radToIndex += UCHAR_MAX; 
     } 
     printf("%d*sin(%f) : %f , %d\n", 
      scalar,rad[i],scalar*sinf(rad[i]),scalar*SIN(radToIndex)); 

    } 
} 

int main() 
{ 
    initTable(); 

    test1(); 
    test2(); 

    return 0; 
} 

आउटपुट:

scalar=123 
123*sin(2.000000) : 111.843582 , 111 
123*sin(4.000000) : -93.086708 , -92 
123*sin(6.000000) : -34.368107 , -32 
123*sin(8.000000) : 121.691063 , 121 
123*sin(10.000000) : -66.914597 , -67 
123*sin(-2.000000) : -111.843582 , -111 
123*sin(-4.000000) : 93.086708 , 92 
123*sin(-6.000000) : 34.368107 , 32 
123*sin(-8.000000) : -121.691063 , -121 
123*sin(-10.000000) : 66.914597 , 67 
scalar=123 
123*sin(0.010000) : 1.229980 , 0 
123*sin(0.100000) : 12.279510 , 12 
123*sin(1.000000) : 103.500931 , 103 
123*sin(10.000000) : -66.914597 , -67 
123*sin(100.000000) : -62.282974 , -63 
123*sin(1000.000000) : 101.706184 , 102 
123*sin(-0.010000) : -1.229980 , 0 
123*sin(-0.100000) : -12.279510 , -12 
123*sin(-1.000000) : -103.500931 , -103 
123*sin(-10.000000) : 66.914597 , 67 
123*sin(-100.000000) : 62.282974 , 63 
123*sin(-1000.000000) : -101.706184 , -102 
संबंधित मुद्दे