9

Vì vậy, tôi có một chức năng mà trông giống như sau:Có thể cout thay đổi biến bằng cách nào đó không?

float function(){ 
    float x = SomeValue; 
    return x/SomeOtherValue; 
} 

Tại một số điểm, chức năng này tràn và trả về một giá trị tiêu cực thực sự lớn. Để thử và theo dõi chính xác nơi xảy ra sự cố này, tôi đã thêm tuyên bố cout để chức năng trông như sau:

float function(){ 
    float x = SomeValue; 
    cout << x; 
    return x/SomeOtherValue; 
} 

và đã hoạt động! Tất nhiên, tôi đã giải quyết vấn đề hoàn toàn bằng cách sử dụng một đôi. Nhưng tôi tò mò là lý do tại sao chức năng này hoạt động đúng khi tôi couted nó. Đây có phải là điển hình, hoặc có thể có một lỗi ở một nơi khác mà tôi đang thiếu?

(Nếu đó là bất kỳ sự giúp đỡ, giá trị được lưu trữ trong các phao chỉ là một giá trị số nguyên, và không phải là một đặc biệt lớn. Tôi chỉ cần đặt nó trong một phao để tránh đúc.)

Trả lời

18

Chào mừng bạn đến với thế giới tuyệt vời của điểm nổi. Câu trả lời bạn nhận được có thể sẽ phụ thuộc vào mô hình điểm nổi mà bạn đã biên dịch mã.

Điều này xảy ra do sự khác biệt giữa thông số IEEE và phần cứng đang chạy. CPU của bạn có khả năng có các thanh ghi dấu phẩy động 80 bit để sử dụng để giữ giá trị nổi 32 bit. Điều này có nghĩa rằng có độ chính xác cao hơn nhiều trong khi giá trị nằm trong một thanh ghi hơn khi nó bị buộc vào một địa chỉ bộ nhớ (còn được gọi là 'homing' thanh ghi).

Khi bạn vượt qua giá trị để cout trình biên dịch phải ghi điểm nổi vào bộ nhớ, và điều này dẫn đến việc mất chính xác và hành vi thú vị các trường hợp tràn WRT.

Xem tài liệu MSDN trên VC++ floating point switches. Bạn có thể thử biên dịch với/fp: nghiêm ngặt và xem điều gì xảy ra.

+0

Ngoài ra còn có một lưu ý GCC cho việc này tại http://gcc.gnu.org/wiki/x87note Do hành vi tuyệt vời này, so sánh các tính toán điểm động cũng bị hỏng, trừ khi sử dụng các giá trị được tính trước. – hazzen

3

In một giá trị cho cout không nên thay đổi giá trị của paramter theo bất kỳ cách nào.

Tuy nhiên, tôi đã thấy hành vi tương tự, việc thêm các câu lệnh gỡ lỗi làm thay đổi giá trị. Trong những trường hợp đó, và có lẽ điều này cũng như dự đoán của tôi là các câu lệnh bổ sung đã làm cho trình tối ưu hóa của trình biên dịch hoạt động khác nhau, do đó tạo ra các mã khác nhau cho hàm của bạn.

Thêm câu lệnh cout có nghĩa là vaue của x được sử dụng trực tiếp. Không có nó, trình tối ưu hóa có thể loại bỏ biến, do đó thay đổi thứ tự của phép tính và do đó thay đổi câu trả lời.

0

Tôi không nghĩ rằng cout có bất kỳ ảnh hưởng nào đến biến, vấn đề sẽ phải ở một nơi khác.

2

Là một sang một bên, nó luôn luôn là một ý tưởng tốt để khai báo các biến bất biến sử dụng const:

float function(){ 
    const float x = SomeValue; 
    cout << x; 
    return x/SomeOtherValue; 
} 

Trong số những thứ khác này sẽ ngăn cản bạn vô tình đi qua các biến của bạn để chức năng mà có thể sửa đổi chúng thông qua tài liệu tham khảo không const .

1

cout gây ra một tham chiếu đến biến, thường sẽ làm cho trình biên dịch buộc nó tràn vào ngăn xếp.

Bởi vì nó là một phao, điều này có khả năng làm cho giá trị của nó được cắt ngắn từ biểu diễn kép đôi hoặc dài nó thường sẽ có.

Gọi bất kỳ hàm nào (không được gạch chân) lấy con trỏ hoặc tham chiếu đến x sẽ kết thúc gây ra hành vi tương tự, nhưng nếu trình biên dịch sau đó trở nên thông minh hơn và học nội tuyến, bạn sẽ bị làm như vậy :)