golang 不同类型之间计算的float32 精度 golang问题怎么解决

博客分类:
很简单的一件事,但是如果不知道的话一样很麻烦。Number包里的两个方法可以轻松解决,而不是Math包里。下面是官方文档:
toFixed(3) 如何返回舍入到小数点后三位的字符串。
var num:Number = 7.31343;
trace(num.toFixed(3)); // 7.313
toFixed(2) 如何返回添加尾随 0 的字符串。
var num:Number = 4;
trace(num.toFixed(2)); // 4.00
toPrecision(3) 如何返回只包含三位数的字符串。 由于不需要指数表示法,因此字符串使用定点表示法。
var num:Number = 31.570;
trace(num.toPrecision(3)); // 31.6
toPrecision(3) 如何返回只包含三位数的字符串。 由于结果数字中没有足够的位数来使用定点表示法,因此字符串使用指数表示法。
var num:Number = 4000;
trace(num.toPrecision(3)); // 4.00e+3
----------------------------------------------------------------------------------------------------------------------------------注意哦 toFixed()和toPrecision() 返回的是String类型,而不是字符串类型。另外Math包里的round() ,只能返回整数。
浏览: 12825 次
来自: 成都
FB4.7我在 一个s:button 里直接绑定 skinCl ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'下次自动登录
现在的位置:
& 综合 & 正文
golang:一个高性能低精度timer实现
在go自带的timer实现中,采用的是通常的最小堆的方式,具体可以参见。
最小堆能够提供很好的定时精度,但是,在实际情况中,我们并不需要这样高精度的定时器,譬如对于一个连接,如果它在2分钟以内没有数据交互,我们就将其删除,2分钟并不需要那么精确,多几秒少几秒都无所谓的。
以前我们单独实现了一个,采用的是channel close的方式来处理低精度,超大量timer定时的问题,详见。
但是timingwheel只有After接口,远远不能满足实际的需求,于是我按照linux timer的实现方式,依葫芦画瓢,弄了一个go版本的实现。linux timer的实现,参考。
后续用go timer来表示我自己实现的timer。
在linux中,我们使用tick来表示一次中断的时间,用jiffies来表示系统自启动以来流逝的tick次数。在go timer中,我们在创建一个wheel的时候,需要指定一次tick的时间,如下:
func NewWheel(tick time.Duration) *Wheel
Wheel是go timer统一对timer进行管理的地方。对于每一次tick,我们采用go自带的ticker进行模拟。
为了便于外部使用,我仍然提供的是跟go自己timer一样的接口,譬如:
func NewTimer(d time.Duration) *Timer
在NewTimer中,参数d是一个time duration,我们还需要根据tick来进行换算,得到go timer中实际的expires,也就是在多少次jiffies后该timer触发。
譬如,NewTimer参数为10s,tick为1s,那么经过10个jiffies之后,该timer就会超时触发。如果tick为500ms,那么需要经过20个jiffies之后,该timer才会被触发。
所以timer超时jiffies的计算如下:
expires = wheel.jiffies + d / wheel.tick
详细的代码在。
&&&&推荐文章:
【上篇】【下篇】25个关键字
  程序声明:import, package
  程序实体声明和定义:chan, const, func, interface, map, struct, type, var
  程序流程控制:go, select, break, case, continue, default, defer, else, fallthrough, for, goto, if, range, return
  18个基本类型:bool, string, rune, byte, int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64, complex64, complex128
  7个复合类型:array, struct, function, interface, slice, map, channel
  其中,切片、字典、通道类型都是引用类型
  类型的声明一般以 type 关键字开始,然后是自定义的标识符名称,然后是基本类型的名称或复合类型的定义。
  Unicode字符rune类型是和int32等价的类型,通常用于表示一个Unicode码点。这两个名称可以互换使用。同样byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。
  最后,还有一种无符号的整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。&
  一个float32类型的浮点数可以提供大约6个十进制数的精度,而float64则可以提供约15个十进制数的精度;通常应该优先使用float64类型,因为float32类型的累计计算误差很容易扩散,并且float32能精确表示的正整数并不是很大
  列举一些特殊的操作符,注意下面的位操作符
位运算 AND
位运算 XOR
位清空 (AND NOT)
  可以通过 Printf 函数的 %b 参数来输出二进制格式的数字。
特殊的空标识符
  下划线 _ 作为一个特殊的标识符,可以用于 import 语句中,仅执行导入包中的 init 方法。也可以作为赋值语句的左边,表示该变量并不关心且不使用。
  此外,标识符首字母的大小写,在GO语言中被用来控制变量或函数的访问权限,类似于其它语言的 public\private。
  比较特殊的表达式有类型断言,如果判断一个表达式 element&的类型是 T 的话,表达式为 element.(T),意思是 element&不为 nil 且存储在其中的值是T类型。这里有两种情况,如果 T 不是一个接口类型,则 element&必须要为接口类型的值,比如判断 100 是 int 型,不能使用 100.(int),而要用 interface{}(100).(int) ; 如果T 是一个接口类型,表示断言 element&实现了 T 这个接口。如果函数的参数是一个空接口,则必须断言传入的接口实现类型,才能使用其对应的方法。
可变参函数
  最后一个参数为 ...T 的形式的函数即为可变参函数,意味着可变参数都是 T 类型(或实现了T的类型)如:func CallFunction(first string, t ...string),GO语言会在调用可变参函数时,创建一个切片,然后将这些可变参数放入切片中,但如果传入的可变参部分就是一个元素类型为T的切片的话,则直接把传入切片赋值给创建的切片,且在调用写法上也有区别,为: CallFunction("hello", []string{"x","y"}...)&
  array: 声明一个长度为 n 、元素类型为 T 的数组为: [n]T, 元素类型可以为基本类型也可以为复合类型,也可以不指定 n ,由推导得出,如: [...]string{"a","b"} , 数组长度 n = len([...]string{"a","b"}),另外如果指定了数组长度,但定义的数组长度小于声明的长度,则以声明长度为准,不足的元素补默认值。同一元素类型,但数组长度不同,则视为不同类型。
  slice: 切片类型的声明为 []T数组,切片类型里没有关于长度的规定,其它跟数组一样,切片类型的零值是 nil。切片总是对应于一个数组,其对应的数组称为底级数组。切片和其底层数组的关系是引用关系,如果有修改都会影响到对方。
  切片的数据结构包含了指向其底层数组的指针、切片长度和切片容量。切片的长度很容易理解,切片的容量是什么呢,它是切片第一个元素到底层数组最后一个元素的长度。
  map: 定义一个哈希表的格式为 map[K]V,其中 K 表示键的类型,V表示值的类型,如: map[string]bool{"IsOK":true, "IsError":false}
  定义了一组方法声明,接口中可以包含接口
  GO语言对接口类型的实现是非侵入式的(备注:侵入式是指用户代码与框架代码有依赖,而非侵入式则没有依赖,或者说耦合),只要一个类型定义了某个接口中声明的所有方法,就认为它实现了该接口。
  一个特殊的接口: interface{} 是一个空接口,不包含任何方法声明,所以GO语言所有的类型都可以看成是它的实现类型,我们就可以使用它实现类似其它语言中的公共基类的功能。比如声明一个字典,键是字符串,值是不确定类型,就可以使用 map[string]interface{}&
  判断一个类型是否实现了一个接口,可以通过类型断言来确定: _, ok := interface{}(MyType{}).(MyInterface)
函数与方法
  GO语言中,函数跟方法是有区别的,函数就是我们通常理解的函数,而方法是附属于某个自定义数据类型的函数,即存在某个接收者。
  func (self MyType) Len() int {} & & 这里的 (self MyInterface) 是表示方法接收者。
  值方法和指针方法,值方法是指接收者是一个对象,而指针方法是指接收者是一个对象指针。两者的区别是,值方法中对接收者的改变是副本级别的,而指针方法中对接收者的改变是地址级别的。所以其实一般都推荐使用指针方法,因为大多数情况下我们在方法内部修改接收者,都是为了真实的改变它,而不是改变一个副本。但是,对于引用类型的接收者来说,两者并无区别。
  匿名函数由函数字面量表示,函数是作为值存在的,可以赋给函数类型的变量。如:
var myfunc func(int, int) int
myfunc = func(x, y int) (result int) {
result = x + y
log.Println(myfunc(3, 4))
  一个方法的类型是一个函数类型,即把接收者放到函数的第一个参数位置即可。
  非常遗憾,GO语言不支持函数和方法重载。
  可以包含字段,也可以包含匿名字段,一般匿名字段是接口类型,这样就相当于该结构体包含了该接口中的方法,另外也可以在结构里重写隐藏接口中的方法。
  有一个专门用于存储内存地址的类型 unitptr,它与 int/unit 一样属于数值类型,存储32/64位无符号整数。
  可以在一个类型前面使用*号,来表示对应的指针类型,也可以在可寻址的变量前面使用&,来获取其地址。
  定义常量和多个常量如下:
const PP = iota
const QQ = iota
log.Print(A, B, C, D, E, F)
//输出是: 1 2 2 3 4 5
  注意,iota 只能在 const 里使用,它是 const 的行数索引器,其值是所在const组中的索引值,单常量定义时 iota 就等于 0。另外,const组中某一项如果不赋值,则默认和上一个值一样,但如果前面是 iota ,则为上一个值+1。使用 iota 可以实现其它语言中的枚举。
  变量的声明语句以 var 开始,声明多个变量时,和声明多个const的方法相同。
var x string = "df"
var x = "df"
//此为简写形式。
数据初始化
  GO语言的数据初始化有两种方法,一是使用 new ,一是使用 make ,其中 new 是为某个类型分配内存,并设置零值后返回地址,如 new(T) 返回的就是指向T类型值指针值,即*T。如 new([3]int) 其实相当于 [3]int{0,0,0},所以它是一种很干净的内存分配策略。
  make 只用于创建切片类型、字典类型和通道类型(注意这三个类型的特点,都是引用类型),它对这些类型创建之后,还会进行必要的初始化,与 new 不同,它返回的就是指T类型的值,而不是指针值。
定义常量的方式是使用 const ,如 const PI = 3.14,如果定义多个常量可以使用&
编译器会自动选择在栈上还是在堆上分配局部变量的存储空间,但可能令人惊讶的是,这个选择并不是由用var还是new声明变量的方式决定的。 如果一个函数里声明一个局部变量,但是将其指针赋给一个全局变量,那么则不能将此局部变量放在栈中,而只能放在堆中,我们可以称之为该局部变量逃逸了,所以关于变量是分配在栈上还是堆上,是由编译器根据情况来选择的。
  close 只接受通道类型的值
  len函数,可以应用于字符串、切片、数组、字典、通道类型
  cap函数,可以应用于切片、数组、通道类型
  new函数和make函数
  append函数和copy函数,应用于切片
  delete函数,根据字典的键删除某一项
  complex\real\imag函数,复数相关
  panic 函数,异常相关,它的参数一般是某个error接口的某个实现类型;recover 函数,不接受任何参数,返回 interface{} 类型,也就是意味着,它可以返回任意类型。recover返回的内容是与panic相关的,就是panic的参数内容。
  print\println 函数,这两个函数支持基本类型参数,且是可变参数。但输出格式是固定的,且GO语言不保证以后会保留这两个函数,所以知道就好,不推荐使用。可以使用 fmt.Print 和 fmt.Println 来代替,效果更佳。
合并书写:
和 var/const 类似,多个 type 定义可合并成组,如下:
Person struct {
Name string
myfunc func(string) bool
&尤其是在函数内部定义一堆临时类型时,可集中书写,可读性更好。
自增/自减运算符不同于其它语言,不能用作表达式,只能当独立的语句使用,且不能前置,只有后置形式,以尽可能避免该运算符带的复杂性问题。
unsafe.Pointer 与 uintptr 的区别:
前者类似 C 语言中的 void* 万能指针,能安全持有对象,但后者不行,后者只是一种特殊整型,并不引用目标对象,无法阻止垃圾回收器回收对象内存。
阅读(...) 评论()学习Golang语言(3):类型--布尔型和数值类型 - Golang中国
22:00 发布 5250 次点击
学习Golang语言(3):类型--布尔型和数值类型
跟着“码术”一起学习Golang语言。今天讲解Golang语言的基本类型,介绍布尔类型和数值类型。
布尔类型是 bool。Go语言提供了内置的布尔值true和flase。Go语言支持标准的逻辑和比较操作。这些操作的结果都是布尔值。
布尔值和表达式可以用于if语句中,for语句的条件中以及switch语句的case的判断中。
逻辑操作符:
!:逻辑非操作符;
||:逻辑或操作符;
&&:逻辑与操作符;
比较操作符。
&,&, ==,!=, &=, &=
整形和浮点型
Go语言提供大量内置的数值类型。众所周知的类型如int,这个类型根据你的系统决定适当的长度。在32位系统上是32位,在64位系统上是64位。因此在Go语言中,int和int32是不同类型。如果你希望明确其长度,可以使用int32或者int64等等。
完整的整数类型(符号和无符号)是int8,int16,int32,int64 和 byte,uint8,uint16,uint32,uint64。其中byte 是 uint8 的别名。
浮点类型的值有 float32 和 float64 (没有 float 类型)。64 位的整数和浮点数总是 64 位的,即便是在 32 位的架构上。
整形变量的默认赋值是0,浮点型变量的默认赋值是0.0
需要注意的是:这些类型全部都是独立的,并且混合使用这些类型向变量赋值会引起编译器错误。例如:
package main
func main(){
//通用整数类型
var b int32 // 32位整数类型
// 混合这些类型是非法的,这会导致编译异常
// 5是常量(未定义类型),所以没有问题
如果不同数值类型之间进行数值运算或者比较操作时,需要进行类型转换。通常将类型转换成最大的类型以防止精度丢失。类型转换采用type(value)的形式。当将类型转换为小的类型时,为了防止防止精度丢失,我们可以创建合适的函数。例如:将int型转换为uint8
func Uint8FromInt(n int) (uint8, error) {
if 0 &= n && n &= math.MaxUint8 {// conversion is safe
return uint8(n), nil
return 0, fmt.Errorf(“%d is out of the uint8 range”, n)
Go原生支持复数。复数有两种类型:complex64(实部虚部都是一个float32)和complex128 (实部虚部都是一个float64)。复数的形式为:re+im i。其中re为实部,im为虚部。
复数可以使用内置的complex()函数或者包含虚部数值的常量来创建。复数的各个部分可以使用内置函数real()和imag()函数获得。
var c1 complex64 = 5 + 10i
fmt.Printf(“The value is: %v”, c1)
// 这里会输出: 5 + 10i
c := complex(50,100);
fmt.Printf(“The value is: %v”, c1)
//这里会输出: 50 + 100i
复数支持所有的算术操作符。唯一可以用于复数的比较操作符号是 == 和!=。
标准库中有一个复数包 math/cmplx 提供复数各种通用的操作函数。
如果不需要考虑内存问题,尽量使用complex128类型,因为标准库中所有函数都是使用complex128类型。
欢迎关注码术!一起学习golang.
后方可回复, 如果你还没有账号你可以
一个帐号。
欢迎关注码术!double类型计算精度确实问题
<span type="1" blog_id="1912459" userid='
分享到朋友圈
喜欢我的文章,请分享到朋友圈

我要回帖

更多关于 浮点数计算精度问题 的文章

 

随机推荐