Làm thế nào để làm tròn số dấu phẩy động trong vỏ?


13

Làm cách nào để làm tròn chính xác các số dấu phẩy động IEEE 754 trên dòng lệnh?

Tôi muốn chỉ định độ chính xác của số đầu ra - số lượng các chữ số phân số.

Làm tròn 6.66đến độ chính xác 1sẽ cho 6.7, ví dụ. Thêm trong bảng dưới đây:

Value   Precision  Rounded
6.66    0          7
6.66    1          6.7
6.66    2          6.66
6.66    3          6.660
6.666   3          6.666
6.6666  3          6.667

Nó có thể được sử dụng trong một vỏ tương tác, nhưng đủ mạnh để sử dụng nó trong các kịch bản shell sản xuất.


Tôi sẽ sử dụng awk.
đẳng cấu

Câu trả lời:


30

Làm tròn số dấu phẩy động

"Làm tròn số dấu phẩy động" nghĩa là gì?
Điều đó thật dễ dàng, rõ ràng ... Cuốn sách toán học của tôi ở đâu ...

Không, chúng tôi đã biết không có gì liên quan đến số dấu phẩy động là dễ dàng:

Để bắt đầu, có nhiều chế độ làm tròn:

Làm tròn lên?
Làm tròn xuống?
Làm tròn đến không?
Làm tròn đến gần nhất - quan hệ để thậm chí?
Làm tròn đến gần nhất - quan hệ từ số không?

Làm thế nào để xử lý các trường hợp góc? Làm thế nào để tìm ra những trường hợp góc?

OK, có vẻ như chúng tôi sử dụng tốt hơn việc triển khai tiêu chuẩn IEEE 754 và để hệ thống của chúng tôi xử lý vấn đề đó.

Để làm tròn số dấu phẩy động trong vỏ, dựa trên số học dấu phẩy động tiêu chuẩn, chúng ta cần ba bước:

  • Chuyển đổi văn bản đầu vào từ một đối số dòng lệnh thành một số dấu phẩy động tiêu chuẩn.
  • Làm tròn số dấu phẩy động bằng cách sử dụng triển khai IEEE 754 bình thường.
  • Định dạng số dưới dạng một chuỗi cho đầu ra.

Hóa ra lệnh shell printfcó thể làm tất cả những điều này. Nó có thể được sử dụng để in số theo một đặc điểm kỹ thuật định dạng như được mô tả trong man 3 printf. Các số được làm tròn hoàn toàn theo cách tiêu chuẩn nếu được yêu cầu cho định dạng đầu ra:

Lệnh

Làm tròn xđến pchữ số chính xác với đầu vào là đối số dòng lệnh:

printf "%.*f\n" "$p" "$x"

Hoặc trong một đường ống vỏ, với đầu vào của đầu xvào tiêu chuẩn và plàm đối số:

echo "$x" | xargs printf "%.*f\n" "$p"

Ví dụ:

$ printf '%.*f\n' 0 6.66
7
$ printf '%.*f\n' 1 6.66
6.7
$ printf '%.*f\n' 2 6.66
6.66
$ printf '%.*f\n' 3 6.66
6.660
$ printf '%.*f\n' 3 6.666
6.666
$ printf '%.*f\n' 3 6.6666
6.667

Bẫy xấu

Hãy coi chừng miền địa phương! Nó chỉ định dấu phân cách giữa phần tích phân và phần - .như bạn có thể mong đợi.
Nhưng hãy xem chính bạn những gì xảy ra ở một địa phương của Đức, ví dụ:

$ LC_ALL=de_DE.UTF-8 printf '%.*f\n' 3 6.6666
6,667

Vâng, điều đó đúng 6,667- sáu dấu phẩy sáu sáu bảy. Điều đó sẽ gây rối cho kịch bản của bạn chắc chắn.
(Nhưng chỉ dành cho hai khách hàng ở Đức. Ngoại trừ máy của nhà phát triển hiện đang gỡ lỗi cho những khách hàng này.)

Mạnh mẽ hơn

Để làm cho nó mạnh mẽ hơn, sử dụng:

LC_ALL=C /usr/bin/printf "%.*f\n" "$p" "$x"

hoặc là

echo "$x" | LC_ALL=C xargs /usr/bin/printf "%.*f\n" "$p"

Điều này cũng sử dụng /usr/bin/printfthay vì vỏ dựng sẵn bashhoặc zshđể khắc phục những mâu thuẫn nhỏ trong việc thực hiện các printfbiến thể, và ngăn chặn hiệu ứng rất bẩn khi, tại một địa điểm của Đức, LC_ALLđược đặt, nhưng không được xuất. Sau đó, nội dung được sử dụng ,/usr/bin/printfsử dụng ....


Xem thêm %gđể làm tròn đến một số chữ số có nghĩa.


0

Sau đây làm việc cho tôi.

#!/bin/bash
function float() {
bc << EOF
num = $1;
base = num / 1;
if (((num - base) * 10) > 1 )
    base += 1;
print base;
EOF
echo ""
}

float 3.2
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.