Chapter 18: Float
Float
Floating-point numbers are the ones that can represent decimal / fractional values (3.14, -0.001, 1.7976931348623157e+308, etc.).
In Go, floating-point support is very simple and clean compared to many other languages: only two types exist, and one of them is overwhelmingly preferred.
Let’s go through everything step by step like we’re sitting together with VS Code open and a notebook.
1. The Two Floating-Point Types in Go
| Type | Bits | Approx. decimal digits of precision | Approx. range (positive values) | Zero value | Recommendation / Reality in 2026 |
|---|---|---|---|---|---|
| float32 | 32 | ~6–7 digits | ±1.18×10⁻³⁸ to ±3.40×10³⁸ | 0.0 | Use only when memory is extremely tight |
| float64 | 64 | ~15–16 digits | ±2.23×10⁻³⁰⁸ to ±1.80×10³⁰⁸ | 0.0 | Default and almost always the correct choice |
Key takeaway most people learn the hard way:
In modern Go code (2024–2026), you should almost never use float32 unless you have a very specific reason (GPU memory, legacy file formats, very large arrays of floats where every 4 bytes matters).
The default floating-point literal type is float64.
2. Declaration & Literal Examples
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package main import "fmt" func main() { // Most common & recommended style pi := 3.141592653589793 // float64 (default) gravity := 9.80665 // float64 verySmall := 1.23e-10 // scientific notation → float64 veryLarge := 1.7976931348623157e+308 // approx max float64 // Explicit float32 (rare) var smallFloat float32 = 3.14 // Zero values var uninitFloat64 float64 var uninitFloat32 float32 fmt.Printf("pi: %.15f (type %T)\n", pi, pi) fmt.Printf("gravity: %.5f (type %T)\n", gravity, gravity) fmt.Printf("verySmall: %e (type %T)\n", verySmall, verySmall) fmt.Printf("smallFloat: %.3f (type %T) ← explicit float32\n", smallFloat, smallFloat) fmt.Printf("uninit: %f ← zero value for both\n", uninitFloat64) } |
Typical output:
|
0 1 2 3 4 5 6 7 8 9 10 |
pi: 3.141592653589793 (type float64) gravity: 9.80665 (type float64) verySmall: 1.230000e-10 (type float64) smallFloat: 3.140 (type float32) ← explicit float32 uninit: 0.000000 ← zero value for both |
3. Literal Styles You’ll See
| Style | Example literal | Result type | Notes |
|---|---|---|---|
| Decimal | 3.14 | float64 | Most common |
| With exponent (scientific) | 1.23e-4 or 9.8E+2 | float64 | e or E both ok |
| Hexadecimal float (Go 1.13+) | 0x1.8p1 | float64 | Rare — used in low-level math / tests |
| No decimal point | 42. or .5 | float64 | Both valid |
4. Important Characteristics & Gotchas (Must Know)
a) Precision is not infinite
|
0 1 2 3 4 5 6 7 8 9 10 11 |
a := 0.1 b := 0.2 sum := a + b fmt.Printf("%.20f\n", sum) // 0.30000000000000004441 ← not exactly 0.3 fmt.Println(sum == 0.3) // false |
→ Classic floating-point imprecision (IEEE 754 standard). → Never compare floats with == for equality unless you really understand what you’re doing.
b) Safe comparison pattern (use small epsilon)
|
0 1 2 3 4 5 6 7 8 9 10 |
const epsilon = 1e-9 if abs(sum-0.3) < epsilon { fmt.Println("Approximately equal") } |
c) No automatic promotion from float32 → float64 in most cases
|
0 1 2 3 4 5 6 7 8 9 10 11 |
var f32 float32 = 3.14 var f64 float64 = f32 // ok — implicit conversion f64 = 2.718 // ok // f32 = f64 // ERROR — possible loss of precision f32 = float32(f64) // explicit — allowed, but may lose precision |
5. Real-World Use Cases (2026 style)
| Use case | Recommended type | Why |
|---|---|---|
| Scientific calculations | float64 | Needs high precision |
| Money / finance | none — use decimal package | float64 can give rounding surprises |
| Machine learning weights/biases | float32 or float64 | float32 often used to save GPU memory |
| Game physics / 3D coordinates | float32 or float64 | Depends on engine (Unity → float32, many Go engines → float64) |
| JSON / config values | float64 | json.Unmarshal defaults to float64 |
| Very large arrays of floats | float32 | 50% memory saving |
| GPS coordinates, distances | float64 | Needs enough precision |
6. Quick Practice Exercise (Try Right Now)
Create float_practice.go:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package main import ( "fmt" "math" ) func main() { // 1. Normal usage radius := 5.7 area := math.Pi * radius * radius fmt.Printf("Circle radius %.1f → area ≈ %.4f\n", radius, area) // 2. Show precision difference var f32 float32 = 0.1 + 0.2 var f64 float64 = 0.1 + 0.2 fmt.Printf("float32: %.20f\n", f32) fmt.Printf("float64: %.20f\n", f64) // 3. Safe comparison helper approxEqual := math.Abs(f64-0.3) < 1e-10 fmt.Println("0.1 + 0.2 ≈ 0.3 ?", approxEqual) } |
Run it → observe the tiny difference between float32 and float64.
Any part still confusing?
- Floating point precision & rounding deeper?
- math package helpers (math.Abs, math.Round, etc.)?
- float32 vs float64 in JSON marshaling/unmarshaling?
- Or next: string type in detail? or composite types (slice/struct/map)?
You’re progressing beautifully — keep running these small examples, they build intuition very fast. 💻🇮🇳 Let’s keep going! 🚀
