2013-07-30 45 views
5

Tôi đã đoạn mã sau cho tứ phân vị tìm:Các bội số của 0,25 chính xác có thể biểu diễn dưới dạng gấp đôi không?

#include <stdio.h> 
#include <stdlib.h> 

typedef struct { 
    double qrt[3]; 
    double *value; 
    int count; 
} t_data; 

static void set_qrt(t_data *data, int qrt) 
{ 
    int n, e; 
    double d; 

    d = qrt * 0.25 * data->count + 0.5; 
    n = (int)d; 
    e = n != d; 
    data->qrt[qrt - 1] = data->value[n - 1]; 
    if (e) { 
     data->qrt[qrt - 1] += data->value[n]; 
     data->qrt[qrt - 1] *= 0.5; 
    } 
} 

static void set_qrts(t_data *data) 
{ 
    set_qrt(data, 2); 
    if (data->count > 1) { 
     set_qrt(data, 1); 
     set_qrt(data, 3); 
    } else { 
     data->qrt[0] = 0.0; 
     data->qrt[2] = 0.0; 
    } 
} 

static int comp(const void *pa, const void *pb) 
{ 
    const double a = *(const double *)pa; 
    const double b = *(const double *)pb; 

    return (a > b) ? 1 : (a < b) ? -1 : 0; 
} 

int main(void) 
{ 
    double values[] = {3.7, 8.9, 7.1, 5.4, 1.2, 6.8, 4.3, 2.7}; 
    t_data data; 

    data.value = values; 
    data.count = (int)(sizeof(values)/sizeof(double)); 
    qsort(data.value, data.count, sizeof(double), comp); 
    set_qrts(&data); 
    printf("Q1 = %.1f\nQ2 = %.1f\nQ3 = %.1f\n", data.qrt[0], data.qrt[1], data.qrt[2]); 
} 

d = qrt * 0.25 * data->count + 0.5; 
n = (int)d; 
e = n != d; 

được bảo đảm để làm việc như mong đợi? (e == isinteger (d))

+2

'0,25' là số tăng gấp đôi và' 0,25f' là số dư, kết quả của 'qrt * 0,25 * dữ liệu-> đếm + 0,5;' là gấp đôi. –

+0

Cảm ơn bạn Grijesh, tôi biết về literals, câu hỏi về đại diện nổi với bội số của 0,25 –

+0

thử: 'float qrt = .3f, count = .4f; printf ("% lu", sizeof (qrt * 0,25 * count + 0,5)); 'output phải là ==' sizeof (double) ' –

Trả lời

7

Số 0.5, 0.25, 0.125 và vv đại diện cho quyền hạn tiêu cực của hai và do đó có thể đại diện chính xác trong IEEE 754 types. Sử dụng những con số này không dẫn đến lỗi biểu diễn.

+0

Chỉ vì những con số đó là chính xác, điều đó không có nghĩa là tất cả các tính toán liên quan đến chúng được. Bạn vẫn cần chú ý đến phạm vi giá trị của mình. Không có phím tắt để phân tích số - nếu bạn muốn sử dụng phao, bạn phải cẩn thận. –

+2

@LeeDanielCrocker Câu trả lời của tôi là về quyền hạn tiêu cực của 2 trong bối cảnh vấn đề cụ thể của OP. Tôi đã không về để bao gồm các phân tích số nói chung, vì nó là không khả thi trong các Q & A định dạng, cũng không phải là thích hợp để đáp ứng với một câu hỏi khá cụ thể. – dasblinkenlight

+0

Tôi giải thích câu hỏi của OP là "những phép tính này có chính xác" không? Và câu trả lời đúng cho điều đó, như với tất cả việc sử dụng điểm nổi, là "À, nó phụ thuộc ..." –

1

dasblinkenlight là hoàn toàn chính xác. Các kiểu double/float và số nguyên được lưu trữ khác nhau theo IEEE754. Xem this để có hướng dẫn dễ dàng nếu bạn tò mò về nó.

+0

Video hay !! cảm ơn –

+0

Đó không phải là câu trả lời, đó phải là một nhận xét. –

3

Các giá trị 0,5 và 0,25 sẽ chính xác. Các giá trị trung gian của phép tính của bạn có thể có hoặc không, tùy thuộc vào phạm vi của chúng. IEEE đôi có một mantissa 52-bit, vì vậy họ sẽ chính xác đại diện cho 0,25 con số cần 50 bit hoặc ít hơn trong phần định trị, đó là khoảng 15 chữ số thập phân.

Vì vậy, nếu bạn thêm 0,25 đến 100000000000000 (10^14), bạn sẽ nhận được 100000000000000.25. Nhưng nếu bạn thêm 0,25 đến 10000000000000000 (10^16), bạn sẽ mất phần.

+0

Cảm ơn bạn Lee, tốt bắt, làm cho tôi điều rằng mã tôi sử dụng trông mong manh, bạn có thể đề nghị một cách khác để biết nếu kết quả của (int * int * 0,25 + 0,5) là một số nguyên? –

+2

(d * d * 0,25 + 0,5) sẽ là số nguyên chỉ khi d là chẵn. Khi d là lẻ, nó sẽ là một cái gì đó .25 hoặc .75.Nếu bạn muốn kết quả được thể hiện chính xác, bạn sẽ phải kiểm tra xem d đó có nhỏ hơn 33 triệu hay không. Tôi chắc chắn bạn đã nghe điều này trước đây, nhưng nó lặp lại: nếu bạn thực sự cần mọi thứ chính xác, tại sao bạn lại sử dụng phao nổi? Chỉ vì đầu vào và đầu ra của bạn đến và từ con người có thể là dấu chấm động, đó là không có lý do bạn bị mắc kẹt với chúng trong nội bộ. Sử dụng một biểu diễn có ý nghĩa cho ứng dụng. –

+1

@DavidRF: Nếu bạn muốn kiểm tra nếu 'a * b * 0.25 + 0.5' là một số nguyên, trong đó' a' và 'b' là số nguyên, thì những gì bạn đang thử nghiệm là' (a * b) mod 4' bằng 2. Trong C là '(a * b)% 4 == 2 || (a * b)% 4 == -2', miễn là 'a * b' không tràn. – caf

1

Định dạng điểm nổi chính xác gấp đôi có 53 bit trong phân đoạn của nó trong đó có một ẩn. Điều này có nghĩa rằng nó có thể đại diện cho tất cả các số nguyên dương và âm trong khoảng 2^0 đến 2^53-1.

0 (không) là trường hợp đặc biệt có định dạng riêng.

Khi nói đến khoảng cách 0,25, phạm vi được tính thẳng về phía trước được tính là 2^-2 đến 2^51-0,25. Điều này có nghĩa rằng khá một vài nhưng không có nghĩa là tất cả các bội số của 0,25 là chính xác thể hiện ở định dạng chính xác gấp đôi, chỉ là một số khá nhưng không phải tất cả các số nguyên là chính xác đại diện.

Vì vậy, nếu bạn có khoảng cách chính xác có thể biểu thị là 2^x phạm vi thể hiện là 2^x đến 2^(53 + x) -2^x.

Các vấn đề liên quan