package main

import (
	"fmt"
	"math"
	"reflect"
)

// Go语言提供了两种精度的浮点数，float32和float64。
// 它们的算术规范由IEEE754浮点数国际标准定义，该浮点数规范被所有现代的CPU支持。
func main() {
	// 浮点数类型的取值范围可以从很微小到很巨大。浮点数的范围极限值可以在math包找到。
	fmt.Println(math.MaxFloat32)
	fmt.Println(math.MaxFloat64)

	// 一个float32类型的浮点数可以提供大约6个十进制数的精度，
	// 而float64则可以提供约15个十进制数的精度；
	// 通常应该优先使用float64类型，
	// 因为float32类型的累计计算误差很容易扩散，并且float32能精确表示的正整数并不是很大
	// 译注：因为float32的有效bit位只有23个，其它的bit位用于指数和符号；
	// 当整数大于23bit能表达的范围时，float32的表示将出现误差
	var f1 float32 = 16777216 // 1 << 24
	fmt.Println(f1 == f1+1)   // true

	// 小数点前面或者后面的数都能被省略
	f2, f3 := .2345, 67.
	fmt.Println(reflect.TypeOf(f2), f2) // float64 0.2345
	fmt.Println(reflect.TypeOf(f3), f3) // float64 67

	// 很小或很大的数最好用科学计数法书写，通过e或E来指定指数部分：
	const Avogadro = 6.02214129e23 // 阿伏伽德罗常数
	const Planck = 6.62606957e-34  // 普朗克常数

	// 用Printf格式化输出浮点数时使用%g或者%f，可以用类似于%4.2f这种的格式输出
	// 4表示距离前一个操作数有4个tab，2表示保留两位小数输出
	fmt.Printf("%g", 22.33)
	fmt.Printf("\n %.4f %8.2f", 23.123456, 23.123456)
	fmt.Printf("\n %.4f %8.2f\n", 23.133442, 23343.13456)

	// IEEE754浮点数标准中定义的特殊值的创建和测试：正无穷大和负无穷大，
	// 分别用于表示太大溢出的数字和除零的结果；
	//还有NaN非数，一般用于表示无效的除法操作结果0/0或Sqrt(-1).
	var z float64
	fmt.Println(z, -z, 1/z, -1/z, z/z) // "0 -0 +Inf -Inf NaN"
	// 函数math.IsNaN用于测试一个数是否是非数NaN，math.NaN则返回非数对应的值。
	// 虽然可以用math.NaN来表示一个非法的结果，
	// 但是测试一个结果是否是非数NaN则是充满风险的，因为NaN和任何数都是不相等的
	nan := math.NaN()
	fmt.Println(nan == nan, nan < nan, nan > nan) // "false false false"

	// 如果一个函数返回的浮点数结果可能失败，最好的做法是用单独的标志报告失败，像这样：
	//func compute() (value float64, ok bool) {
	//	// ...
	//	if failed {
	//		return 0, false
	//	}
	//	return result, true
	//}

}
