Tôi đang tìm các vấn đề về mô hình/lỗi dấu phẩy động khá khó hiểu. Đó là một khu vực tôi không quen thuộc và tôi không phải là một lập trình viên C/asm cấp thấp, vì vậy tôi sẽ đánh giá cao một chút lời khuyên.Xử lý ngoại lệ Floating-Point trong C++
Tôi có ứng dụng C++ được xây dựng với VS2012 (VC11) mà tôi đã định cấu hình để ném ngoại lệ dấu chấm động (hoặc chính xác hơn, để cho phép thời gian chạy và/hoặc phần cứng C++ ném các ngoại lệ fp) - và ném khá nhiều trong số chúng trong bản phát hành (được tối ưu hóa), nhưng không phải trong bản dựng gỡ lỗi. Tôi cho rằng điều này là do tối ưu hóa và có lẽ là mô hình dấu chấm động (mặc dù trình biên dịch/fp: chuyển đổi chính xác được đặt cho cả bản phát hành và bản dựng gỡ lỗi).
Câu hỏi đầu tiên của tôi liên quan đến quản lý gỡ lỗi ứng dụng. Tôi muốn kiểm soát nơi mà các ngoại lệ fp được ném ra và chúng được "che khuất" ở đâu. Điều này là cần thiết vì tôi đang gỡ lỗi bản phát hành (tối ưu hóa) (là nơi xảy ra các ngoại lệ fp) - và tôi muốn vô hiệu hóa các ngoại lệ fp trong các chức năng nhất định mà tôi đã phát hiện vấn đề, vì vậy tôi có thể tìm ra các vấn đề FP mới. Nhưng tôi bối rối bởi sự khác biệt giữa việc sử dụng _controlfp_s để làm điều này (mà hoạt động tốt) và trình biên dịch (và #pragma float_control) chuyển đổi "/ fp: ngoại trừ" (mà dường như không có hiệu lực). Sự khác biệt giữa hai cơ chế này là gì? Họ có phải có tác dụng tương tự đối với trường hợp ngoại lệ fp không?
Thứ hai, tôi nhận được một số ngoại lệ "Kiểm tra ngăn xếp dấu chấm động" - bao gồm một ngoại lệ có vẻ như được gửi trong cuộc gọi tới dll GDI +. Tìm kiếm trên web, vài đề cập về ngoại lệ này dường như chỉ ra rằng đó là do lỗi trình biên dịch. Đây có phải là trường hợp này không? Nếu vậy, làm thế nào tôi nên làm việc vòng này? Tốt nhất là vô hiệu hóa tối ưu hóa trình biên dịch cho các chức năng vấn đề, hoặc để vô hiệu hóa các ngoại lệ fp chỉ cho các vùng mã có vấn đề nếu không xuất hiện bất kỳ giá trị dấu phẩy động nào bị trả về? Ví dụ, trong cuộc gọi GDI + (đến GraphicsPath :: GetPointCount) mà ném ngoại lệ này, giá trị số nguyên trả về thực tế có vẻ đúng. Hiện tại tôi đang sử dụng _controlfp_s để vô hiệu hóa các ngoại lệ fp ngay trước cuộc gọi GDI + - và sau đó sử dụng lại lần nữa để bật lại ngoại lệ ngay sau cuộc gọi.
Cuối cùng, ứng dụng của tôi thực hiện nhiều tính toán dấu phẩy động và cần phải mạnh mẽ và đáng tin cậy, nhưng không nhất thiết phải cực kỳ chính xác. Bản chất của ứng dụng là các giá trị dấu phẩy động thường chỉ ra các xác suất, do đó vốn có phần không chính xác. Tuy nhiên, tôi muốn bẫy bất kỳ lỗi logic thuần túy nào, chẳng hạn như chia cho số không. Mô hình fp tốt nhất cho điều này là gì? Hiện nay tôi đang:
- bẫy tất cả các trường hợp ngoại lệ fp (tức EM_OVERFLOW | EM_UNDERFLOW | EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID) sử dụng _controlfp_s và một handler SIGFPE Signal,
- đã kích hoạt denormals-là-zero (DAZ) và tuôn ra -to-zero (FTZ) (tức là _MM_SET_FLUSH_ZERO_MODE (_MM_DENORMALS_ZERO_ON)) và
- Tôi đang sử dụng cài đặt trình biên dịch VC11 mặc định/fp: chính xác với/fp: ngoại trừ không được chỉ định.
Đây có phải là mô hình tốt nhất không?
Cảm ơn và kính trọng!
== "Tôi muốn kiểm soát nơi ngoại lệ fp được ném và vị trí chúng bị" che khuất "." == Ngoại lệ không bao giờ được che mặt nạ. Nếu chúng được đeo mặt nạ thì bạn không nên ném ngoại lệ ngay từ đầu. Nếu bằng cách che mặt, bạn có nghĩa là xử lý các ngoại lệ sau đó, nó phải giống nhau cả trong gỡ lỗi và phát hành. – Ram
Xin chào Ram. Điều này chủ yếu để gỡ lỗi ứng dụng của tôi - tôi muốn vô hiệu hóa các ngoại lệ fp trong các chức năng nhất định mà tôi đã phát hiện sự cố, vì vậy tôi có thể tìm ra các vấn đề mới. Tôi cũng có vấn đề với trường hợp ngoại lệ fp được thực hiện bởi cuộc gọi GDI +. Hiện tại tôi sử dụng _controlfp_s để vô hiệu hóa các ngoại lệ fp ngay trước cuộc gọi - và sau đó sử dụng nó để bật lại ngoại lệ ngay sau đó. Và tôi không chắc chắn tất cả các ngoại lệ fp là nhất thiết có liên quan (ví dụ EM_DENORMAL) - mà tôi giả định là lý do tại sao VC (và các trình biên dịch khác?) Tắt chúng theo mặc định. Tôi có thể làm với lời khuyên về điều này - do đó câu hỏi cuối cùng ở trên. – Jools99
@Ram: Những ngoại lệ này không được nêu ra trong phần mềm, chúng được tạo ra do lỗi FPU. Masking xác định liệu lỗi có trở thành ngoại lệ hay không. Đừng nghĩ về xử lý ngoại lệ C++, 'try' /' catch', hoặc stack unwinding. Đây cũng là ngoại lệ nhưng hành vi khác với ngoại lệ C++. –