13. Angka dan matematika

Angka di Go terbagi dua jenis utama, bisa melakukan aritmetika biasa, dan bisa dipakai bersama package standard library untuk bantuan tambahan. Bab ini membahas apa yang kamu butuhkan untuk logika game: pembulatan, angka acak, matematika dasar, dan berpindah di antara kedua jenis angka.

Integer dan float

Go punya dua tipe angka yang umum:

  • int. Bilangan bulat tanpa bagian desimal: 0, 7, -42.
  • float64. Bilangan dengan titik desimal: 3.14, 0.5, -1.0.

Di Go kamu harus memperhatikan mana yang mana. 7 adalah int, 7.0 adalah float64, dan kedua jenis ini tidak bisa dicampur dalam variabel, seperti yang akan kamu lihat di bawah.

%T memberi tahu mana yang kamu punya:

fmt.Printf("%T\n", 7)    // int
fmt.Printf("%T\n", 7.0)  // float64
fmt.Printf("%T\n", 3.14) // float64

Aritmetika

Operator yang sudah kamu kenal semuanya ada di sini:

Operator Nama Contoh Hasil
+ penjumlahan 3 + 2 5
- pengurangan 7 - 4 3
* perkalian 6 * 7 42
/ pembagian, bilangan bulat 7 / 2 3
/ pembagian, desimal 7.0 / 2 3.5
% modulo (sisa bagi) 7 % 3 1

Dua di antaranya perlu dilihat lebih dekat:

Pembagian / tergantung pada tipenya. Membagi dua bilangan bulat menghasilkan bilangan bulat, dan semua yang ada setelah titik desimal dibuang: 7 / 2 adalah 3. Pembuangannya menuju nol, jadi -7 / 2 adalah -3. Kalau ada desimal dalam perhitungan, hasilnya desimal: 7.0 / 2 adalah 3.5.

Modulo % adalah sisa setelah pembagian bilangan bulat. 7 % 3 adalah 1 karena 7 = 2 * 3 + 1. Ini cara standar untuk bertanya "apakah angka ini genap?" — n % 2 bernilai 0 untuk bilangan genap dan 1 untuk bilangan ganjil positif. Operator ini hanya berlaku untuk bilangan bulat.

fmt.Println(7 / 2)   // 3
fmt.Println(7.0 / 2) // 3.5
fmt.Println(7 % 2)   // 1

Go tidak punya operator pangkat. ^ memang ada, tapi fungsinya sama sekali lain: 2 ^ 8 bisa dikompilasi, berjalan, dan menghasilkan 10. Untuk memangkatkan angka, gunakan math.Pow dari bagian berikutnya.

Buka exercises/13/01-arithmetic.go. Tebak setiap hasil yang tercetak sebelum menjalankannya, lalu jalankan dan periksa.

Package math

Package math di Go punya alat bantu yang paling sering kamu pakai. Impor di samping fmt:

import (
    "fmt"
    "math"
)
Fungsi Kegunaannya
math.Floor(x) Nilai bulat terbesar yang tidak lebih dari x. Floor(3.7) adalah 3.
math.Ceil(x) Nilai bulat terkecil yang tidak kurang dari x. Ceil(3.2) adalah 4.
math.Abs(x) Nilai mutlak. Abs(-5) adalah 5.
math.Sqrt(x) Akar kuadrat.
math.Pow(x, y) x pangkat y. Pow(2, 8) adalah 256.
min(a, b) Yang lebih kecil dari dua angka. Bawaan, tanpa import.
max(a, b) Yang lebih besar dari dua angka. Bawaan, tanpa import.
math.Pi Konstanta 3.1415... (sebuah nilai, bukan fungsi).

Panggil seperti fungsi lainnya:

fmt.Println(math.Floor(3.7)) // 3
fmt.Println(math.Ceil(3.2))  // 4
fmt.Println(math.Sqrt(16))   // 4
fmt.Println(min(7, 3))       // 3
fmt.Println(math.Pi)         // 3.141592653589793

Panggilan-panggilan ini, dan sisa isi tabel, ada di exercises/13/02-math-package.go.

Fungsi-fungsi math menerima dan mengembalikan float64, meskipun hasilnya tercetak sebagai 3. fmt.Println tidak menampilkan titik desimal kalau float64 tidak punya angka di belakangnya. min dan max sudah bawaan Go dan selalu tersedia; keduanya mengembalikan tipe yang sama dengan yang kamu berikan.

Menampilkan desimal dengan %.2f

fmt.Println mencetak float64 dengan caranya sendiri. Untuk jumlah desimal yang tetap, gunakan penanda %.2f di fmt.Printf. Angka 2 adalah jumlah desimal yang ditampilkan, dan nilainya dibulatkan agar pas:

price := 3.14159
fmt.Printf("Price: %.2f\n", price) // Price: 3.14

Gunakan untuk apa pun yang dibaca orang. fmt.Println(1000000.0) mencetak 1e+06, dan 0.1 + 0.2, kalau disimpan dalam variabel, mencetak 0.30000000000000004, karena komputer hanya menyimpan desimal secara mendekati. %.2f menampilkannya sebagai 1000000.00 dan 0.30.

Angka acak

Angka acak ada di package math/rand. Impor di samping fmt, dan panggil dengan bagian terakhir namanya, rand:

import (
    "fmt"
    "math/rand"
)
  • rand.Float64() memberikan float64 dari 0.0 sampai, tapi tidak termasuk, 1.0.
  • rand.Intn(n) memberikan bilangan bulat dari 0 sampai n-1. Untuk dadu enam sisi, tambahkan satu: rand.Intn(6) + 1.
fmt.Println(rand.Float64())     // misalnya 0.6238...
fmt.Println(rand.Intn(6) + 1)   // misalnya 4
fmt.Println(rand.Intn(100) + 1) // misalnya 73

Baris-baris ini ada di exercises/13/03-random.go.

rand.Intn(6) tidak pernah memberikan 6. Hasilnya 0, 1, 2, 3, 4, dan 5, jadi + 1 itulah yang membuatnya menjadi dadu. Lupa menambahkannya adalah bug yang umum, dan mudah terlewat, karena hasilnya tetap terlihat acak.

Mencampur int dan float64

Di sini Go lebih ketat daripada matematika. Dua variabel dengan tipe angka yang berbeda tidak bisa digabungkan.

Buka exercises/13/05-mixed-types.go. File ini tidak bisa dikompilasi:

# command-line-arguments
exercises\13\05-mixed-types.go:12:14: invalid operation: level * bonus (mismatched types int and float64)

level adalah int dan bonus adalah float64. Perbaiki baris itu dengan konversi yang dijelaskan di bawah.

Konversi membuat nilai baru dengan tipe yang kamu sebutkan. Tulis tipenya seperti fungsi:

level := 7
bonus := 1.5
fmt.Println(float64(level) * bonus) // 10.5

total := 7
count := 2
fmt.Println(total / count)                   // 3
fmt.Println(float64(total) / float64(count)) // 3.5

price := 3.99
fmt.Println(int(price)) // 3

Go mewajibkan kamu menulis ini supaya tidak ada yang berubah tipe tanpa sengaja. Baris terakhir menunjukkan mengapa itu penting: int(price) membuang bagian desimalnya. Nilainya tidak dibulatkan, jadi 3.99 menjadi 3. Baris-baris ini ada di exercises/13/04-conversions.go.

Angka yang ditulis langsung di dalam kode, seperti 2 atau 1.5, lebih fleksibel daripada variabel. Go menyebutnya konstanta, dan konstanta mengambil tipe angka apa pun yang dibutuhkan perhitungan selama nilainya muat. Jadi bonus * 2 bisa berjalan meskipun bonus adalah float64 dan 2 terlihat seperti int. level * 1.5 tidak bisa, karena 1.5 tidak muat dalam int:

1.5 (untyped float constant) truncated to int

PR

Starter PR yang membutuhkan package lain menyebutkannya di komentar paling atas. Ingat bahwa ekstensi Go untuk VS Code mungkin menambahkan baris import untukmu saat kamu menyimpan file.

Soal 1 — Luas persegi panjang

Buka exercises/13/homework/01-rectangle-area.go. Dua variabel menyimpan width dan height sebuah persegi panjang. Hitung luasnya dan cetak dengan label, misalnya Area: 24.

Soal 2 — Floor dan ceil

Buka exercises/13/homework/02-floor-and-ceil.go. Sebuah variabel menyimpan float64 3.7. Cetak apa adanya, setelah math.Floor, dan setelah math.Ceil. Tambahkan satu baris komentar yang menjelaskan perbedaan floor dan ceil.

Soal 3 — Lempar dua dadu

Buka exercises/13/homework/03-roll-two-dice.go. "Lempar" dua dadu enam sisi dan cetak hasilnya seperti ini:

Die 1: 4
Die 2: 6
Total: 10

Gunakan rand.Intn untuk lemparannya. Lempar setiap dadu secara terpisah supaya kedua nilainya tidak saling bergantung.

Tantangan — Hipotenusa

Buka exercises/13/homework/04-hypotenuse.go. Dua variabel int menyimpan dua sisi pendek segitiga siku-siku (a dan b). Hitung dan cetak hipotenusa c dengan teorema Pythagoras: c adalah akar kuadrat dari a*a + b*b.

math.Sqrt menerima float64, jadi kamu butuh konversi. Cetak ketiga nilai dengan label. Tampilkan hipotenusa dengan dua angka desimal menggunakan %.2f.

Stuck atau sudah selesai? Buka halaman solusi PR.