Trong lập trình nhúng , cụ thể là automotive, có khi trong một cái sensor trên oto thì phần mềm điều khiển của nó chỉ đơn thuần là 1 chương trình C be bé, không sử dụng đến hệ điều hành. Khi thiết kế phần cứng người ta chọn những con chip …yếu xìu ( CPU max 64 Mhz, Ram chỉ vẻn vẹn vài KB ) và đưa ra những quy tắc viết code rất chặt chẽ. Một trong số đó là khi tính toán tất cả phải sử dụng kiểu dữ liệu nguyên (long, int , short , char ) và không được sử dụng kiểu float/double vì nó sẽ làm chậm hiệu năng của chương trình. Vấn đề nảy sinh từ đây.
Giả sử mình có bài toán thế này :
Tính giá trị điện áp ( Result ) dựa vào giá trị AD theo biểu thức :
Result = ( AD – OFFSET ) * Ratio * Correction
Ratio = 1.15556 ; Correction = 0.950 , OFFSET = 128
Hay Result = ( AD – 128 ) * 1.15556*0.95
Trên những hệ thống Desktop computer với những Intel core I hay AMD ryzen hùng mạnh thì chỉ cần đơn giản làm 1 hàm :
double calculate( unsigned char AD )
{
double Result = ( AD – 128 ) * 1.15556*0.95;
return Result;
}
Tuy nhiên với một yêu cầu …quá đáng là không được sử dụng double/float thì chỗ này phải làm như nào ? May mắn ở đây là các giá trị cần biểu diễn bằng float đều là hằng số ( Ratio và Correction) nên ta có thể sử dụng một phương pháp gọi là fake float.
Ý tưởng của phương pháp này là dùng phân số để biểu diễn số thực, ví dụ
1.5 = 3/2
0.333333 = 1/3
0.25 = 1/4
Do đó ta có thể tính :
0.95 = 95/100
1.15556 = 115556/100000
Bây giờ giả sử AD = 228 cho đơn giản, khi tính bằng double :
Result = 100 * 0.95* 1.15556 = 109.7782
Còn tính bằng int :
Result = 100 * 95 * 115556 / 100000 / 100 = 109
Làm như trên ta có sai số là 0.7782 ( tầm 0.7% ), tạm chấp nhận được. Nếu muốn làm giảm sai số ta cần biểu diễn chi tiết hơn nữa. Còn nếu giá trị float kia là biến thì độ phức tạp sẽ còn tăng thêm
Cuối cùng code trở thành
unsigned int calculate( unsigned char AD ) {
unsigned int Result = ( AD – 128 ) * 115556*95/100000/100;
return Result;
}
Bạn nào quan tâm có thể tìm hiểu thêm trong cuốn Making embedded systems