นี่เป็นวิธีที่ถูกต้องในการแปลงทศนิยมให้เป็นจำนวนเต็มในการทุบตี? มีวิธีอื่นอีกไหม?
flotToint() {
printf "%.0f\n" "$@"
}
%.0f
จะปัดขึ้นหรือลง นั่นคือสิ่งที่คุณต้องการ? คุณสามารถใช้printf "%d\n" "$@" 2>/dev/null
เพื่อสับเศษส่วน
นี่เป็นวิธีที่ถูกต้องในการแปลงทศนิยมให้เป็นจำนวนเต็มในการทุบตี? มีวิธีอื่นอีกไหม?
flotToint() {
printf "%.0f\n" "$@"
}
%.0f
จะปัดขึ้นหรือลง นั่นคือสิ่งที่คุณต้องการ? คุณสามารถใช้printf "%d\n" "$@" 2>/dev/null
เพื่อสับเศษส่วน
คำตอบ:
ในbash
นั้นอาจจะดีเท่าที่ได้รับ ที่ใช้ตัวเชลล์ในตัว หากคุณต้องการผลลัพธ์ในตัวแปรคุณสามารถใช้การทดแทนคำสั่งหรือbash
เฉพาะ (ตอนนี้ยังสนับสนุนโดยzsh
):
printf -v int %.0f "$float"
คุณสามารถทำได้:
float=1.23
int=${float%.*}
แต่นั่นจะลบส่วนที่เป็นเศษส่วนแทนที่จะให้จำนวนเต็มที่ใกล้ที่สุดกับคุณและนั่นจะไม่ทำงานสำหรับค่าที่$float
ชอบ1.2e9
หรือ.12
ตัวอย่างเช่น
โปรดสังเกตข้อ จำกัด ที่เป็นไปได้เนื่องจากการเป็นตัวแทนภายในของการลอยตัว:
$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560
คุณได้รับจำนวนเต็ม แต่มีโอกาสที่คุณจะไม่สามารถใช้จำนวนเต็มนั้นได้ทุกที่
นอกจากนี้ตามที่ระบุไว้โดย @BinaryZebra ในprintf
การใช้งานหลายอย่าง(bash, ksh93, yash, ไม่ใช่ GNU, zsh, dash) จะได้รับผลกระทบจาก locale (ตัวคั่นทศนิยมซึ่งอาจเป็น.
หรือ,
)
ดังนั้นหากการลอยของคุณแสดงด้วยเครื่องหมายจุดเป็นทศนิยมเสมอและคุณต้องการให้มันเป็นเช่นนั้นโดยprintf
ไม่คำนึงถึงตำแหน่งที่ตั้งของผู้ใช้ที่เรียกใช้สคริปต์ของคุณคุณจะต้องแก้ไขโลแคลเป็น C:
LC_ALL=C printf '%.0f' "$float"
ด้วยyash
, คุณสามารถทำได้:
printf '%.0f' "$(($float))"
(ดูด้านล่าง)
printf "%.0f\n" 1.1
ไม่ใช่ POSIX เนื่องจาก%f
ไม่จำเป็นต้องได้รับการสนับสนุนจาก POSIX
POSIXly คุณสามารถทำ:
f2i() {
awk 'BEGIN{for (i=1; i<ARGC;i++)
printf "%.0f\n", ARGV[i]}' "$@"
}
อันนั้นไม่ได้รับผลกระทบจาก locale (เครื่องหมายจุลภาคไม่สามารถเป็นตัวคั่นทศนิยมได้awk
เนื่องจากเป็นอักขระพิเศษในไวยากรณ์อยู่แล้ว ( print 1,2
เช่นเดียวกับprint 1, 2
การส่งผ่านสองอาร์กิวเมนต์ไปprint
)
ในzsh
(ซึ่งรองรับการคำนวณจุดลอยตัว (ตัวคั่นทศนิยมเป็นช่วงเวลาเสมอ)) คุณมีrint()
ฟังก์ชันทางคณิตศาสตร์เพื่อให้จำนวนเต็มที่ใกล้ที่สุดเป็นทศนิยม(เช่นในC
) และint()
เพื่อให้คุณได้จำนวนเต็มจากการลอย (เช่นในawk
) ดังนั้นคุณสามารถทำได้:
$ zmodload zsh/mathfunc
$ i=$((int(rint(1.234e2))))
$ echo $i
123
หรือ:
$ integer i=$((rint(5.678e2)))
$ echo $i
568
อย่างไรก็ตามโปรดทราบว่าในขณะที่double
s สามารถเป็นตัวแทนของตัวเลขที่มีขนาดใหญ่มากจำนวนเต็มมี จำกัด มากขึ้น
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
ksh93 เป็นเชลล์แบบบอร์นตัวแรกที่รองรับการคำนวณเลขทศนิยม ksh93 ปรับการทดแทนคำสั่งให้เหมาะสมที่สุดโดยไม่ใช้ไพพ์หรือฟอร์กเมื่อคำสั่งเป็นคำสั่งในตัวเท่านั้น ดังนั้น
i=$(printf '%.0f' "$f")
ไม่แยก หรือดีกว่า:
i=${ printf '%.0f' "$f"; }
ซึ่งไม่ได้แยกอย่างใดอย่างหนึ่ง แต่ยังไม่ได้ไปปัญหาทั้งหมดของการสร้างสภาพแวดล้อม subshell ปลอม
คุณยังสามารถทำสิ่งต่อไปนี้
i=$((rint(f)))
แต่ระวัง:
$ echo "$((rint(1e18)))"
1000000000000000000
$ echo "$((rint(1e19)))"
1e+19
คุณสามารถทำได้:
integer i=$((rint(f)))
แต่ชอบzsh
:
$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808
ระวังว่าksh93
เลขทศนิยมนั้นอิงตามการตั้งค่าตัวคั่นทศนิยมในโลแคล (แม้ว่า,
จะเป็นตัวดำเนินการทางคณิตศาสตร์ ( $((1,2))
จะเป็น 6/5 ในภาษาฝรั่งเศส / เยอรมัน ... โลแคลและเช่นเดียวกับ$((1, 2))
นั่นคือ 2 ในโลแคลภาษาอังกฤษ) .
Yash ยังสนับสนุนลอยคำนวณจุด แต่ไม่ได้มีฟังก์ชั่นทางคณิตศาสตร์เช่นksh93
/ 'szsh
rint()
คุณสามารถแปลงตัวเลขเป็นจำนวนเต็มได้โดยใช้ไบนารี่หรือโอเปอเรเตอร์เป็นต้น (สามารถใช้งานzsh
ได้ แต่ไม่ใช่ksh93
) โปรดทราบว่ามันตัดส่วนทศนิยมมันไม่ได้ให้จำนวนเต็มที่ใกล้ที่สุด:
$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-9223372036854775808
yash
ให้เกียรติตัวคั่นทศนิยมของโลแคลบนเอาต์พุต แต่ไม่ใช่สำหรับค่าคงที่ตัวอักษรพอยท์ในการแสดงออกทางคณิตศาสตร์ซึ่งสามารถทำให้ประหลาดใจ:
$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator
เป็นวิธีที่ดีที่คุณสามารถใช้ค่าคงที่จุดลอยตัวในสคริปต์ของคุณที่ใช้ช่วงเวลาและไม่ต้องกังวลว่ามันจะหยุดทำงานในสถานที่อื่น แต่ก็ยังสามารถจัดการกับตัวเลขตามที่ผู้ใช้แสดงได้นาน ตามที่คุณจำได้ว่าต้องทำ:
var=$((10.3)) # and not var=10.3
... "$((a + 0.1))" # and not "$(($a + 0.1))".
printf '%.0f\n' "$((10.3))" # and not printf '%.0f\n' 10.3
int=${float%.*}
ทำงานได้ดีมากในสคริปต์ทุบตีของฉัน (เวอร์ชัน 3.2.57 (1) - ปล่อย) บน Mac (รุ่น 10.13.4 (17E199))
,
เป็นเลขฐานสิบ ดูในส่วนเกี่ยวกับLC_ALL=C
bc
- ภาษาเครื่องคำนวณความแม่นยำตามอำเภอใจ
int (ลอย) ควรมีลักษณะดังนี้:
$ echo "$float/1" | bc
1234
เพื่อปัดเศษให้ดีขึ้นใช้สิ่งนี้:
$ echo "($float+0.5)/1" | bc
ตัวอย่าง:
$ float=1.49
$ echo "($float+0.5)/1" | bc
1
$ float=1.50
$ echo "($float+0.5)/1" | bc
2
float=-2; echo "($float+0.5)/1" | bc
-1
คำตอบก่อนหน้านี้ที่ส่งเกือบถูกต้อง: "คุณสามารถทำได้:
float=1.23
int=${float%.*}
แต่นั่นจะลบส่วนที่เป็นเศษส่วนแทนที่จะให้จำนวนเต็มที่ใกล้ที่สุดและนั่นจะไม่สามารถใช้ได้กับค่าของ $ float เช่น 1.2e9 หรือ. 12 เป็นต้น .... "
${float%%.*}
ใช้เพียงแค่
echo ${float%%.*}
1
แฮ็คที่ง่ายมาก ๆ ก็คือ
function float_to_int() {
echo $1 | cut -d. -f1 # or use -d, if decimals separator is ,
}
ตัวอย่างผลลัพธ์
$ float_to_int 32.333
32
$ float_to_int 32
32
sed
แต่cut
การแก้ปัญหาง่ายขึ้น ฉันชอบsed
หรือcut
เนื่องจากเป็น IMHO ที่มีอยู่ในเป้าหมายแบบฝังมากกว่าawk
(ซึ่งยังคงพบได้บ่อยbusybox
กว่าbc
)
ที่เกี่ยวข้อง:
การตอบสนอง@ Stéphane Chazelas awk
ตอบ:
float_to_integer_rounding_nearst() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%.0f", ARGV[i]}' "$@";
}
float_to_integer_rounding_floor() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%d", int( ARGV[i] )}' "$@";
}
printf
ไม่หรือถ้ามีเหตุผลอื่นใดที่จะชอบมากกว่า awk printf
builtin