arduino / arduino/ArduinoCore-API

Dubious code in printFloat(double number, uint8_t digits)

Đang mở
#172 2 bình luận 0 reaction 0 người được giao Xem trên GitHub
bug
Ngôn ngữ chính
C++
Star
306
Fork
150
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

A function named printFloat that prints a double is unfortunate naming!

https://github.com/arduino/ArduinoCore-avr/blob/2ff00ae7d4e85fa422b7918ee12baf56a1f3006e/cores/arduino/Print.cpp#L229

The comment indicates a problem. It works but empirical constants are not good practice!

The range check is needed in order to prevent the integer part of the float overflowing in
https://github.com/arduino/ArduinoCore-avr/blob/2ff00ae7d4e85fa422b7918ee12baf56a1f3006e/cores/arduino/Print.cpp#L247
unsigned long is not necessarily 32 bits so the numeric literal is non-portable.
The constant is actually the unsigned long equivalent of INT_MAX - 1. (The -1 is to allow for rounding but further thought needed to be certain of that).

I have a fix which avoids the need for int_part so the problem no longer arises. It also makes the implementation of %g and %e formats relatively trivial.

* Some testing but far from thorough.
* Uses sig figs for %f format instead of decimal places but that can be changed.
* Precision as a parameter not implemented.
* Consideration should be given to ```printFloat(float f, struct PrintOptions *options)```
* It prints a float but that is more than adequate for most purposes.

I would welcome feedback on the various options before I do anything further.

```
#define F_LARGE 6 /* maximum exponent for F format */
#define F_SMALL -3 /* minimum exponent for F format */
#define E_SIG_FIG 4 /* significant figures for E format */
#define F_SIG_FIG 6

// Buffer size. The +1 allows for the rounding digit.
#if E_SIG_FIG > F_SIG_FIG
#define SIZE (E_SIG_FIG + 1)
#else
#define SIZE (F_SIG_FIG + 1)
#endif

void printFloat(float f) {
int8_t d;
char buffer[SIZE];
bool negative;
bool Eformat = false;
uint8_t start = 1; // index of first digit leaving room for a carry from the rounding
uint8_t dp; // index of first digit after the decimal point
uint8_t finish; // index of extra digit used for rounding
int8_t i; // loop counter (must be signed)

if (isnan(f)) { print("nan"); return; }
if (isinf(f)) { print("inf"); return; }

negative = f < 0.0;
if (negative) { f = -f; print('-'); }

int8_t exponent = 0;
while (f >= 10.0) { exponent++; f /= 10.0; }
while (f < 1.0) { exponent--; f *= 10.0; }

// need one more digit for use when rounding
if (exponent > F_LARGE || exponent < F_SMALL) {
// E format
finish = start + E_SIG_FIG;
dp = 1;
Eformat = true;
}
else {
// F format
finish = start + F_SIG_FIG;
dp = exponent + 1;
}

// store the digit chars into the buffer
for (uint8_t i = start; i <= finish; i++) {
d = (uint8_t)f;
buffer[i] = '0' + d;
f -= d;
// Could check for f==0 here and save some multiplies but larger code size
f *= 10.;
}

// rounding
if (buffer[finish] >= '5') {
i = finish - 1;
buffer[0] = '0';
while (buffer[i] == '9') {
buffer[i] = '0';
i--;
}
buffer[i]++;
}

if (buffer[0] == '1') {
start = 0; // there was a carry from the rounding
}
else {
dp++;
}

if (exponent >= 0) { // positive exponent
for ( i = start; i < dp; i++) {
print(buffer[i]);
}
print('.');
for ( i = dp; i < finish; i++) {
print(buffer[i]);
}
}
else { // negative exponent
if (Eformat) {
print(buffer[start]);
print('.');
for ( i = dp; i < finish; i++) {
print(buffer[i]);
}
}
else { // F format
print("0.");
for (i = 1; i < -exponent; i++) {
print('0');
}
for (i = start; i < finish; i++) {
print(buffer[i]);
}
}
}

if (Eformat) {
print('E');
print(exponent);
}
}
```

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Hướng nghiên cứu

Bắt đầu bằng cách xem xét cores/arduino/Print.cpp, đặc biệt là printFloat và mã kiểm tra phạm vi liên quan. Hãy làm rõ định dạng mong muốn, tham số độ chính xác, cách hoạt động của float so với double và liệu %g và %e có nằm trong phạm vi hay không trước khi thay đổi phần triển khai. Để được coi là hoàn tất, cần đạt được sự thống nhất về các tùy chọn đó và thực hiện thêm các kiểm thử ngoài phạm vi kiểm thử hạn chế đã mô tả.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
cpp
Lĩnh vực
embedded-iot
Loại issue
Tái cấu trúc
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Cần làm rõ
Mức phù hợp với người mới
25/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.