文档章节

Unity net平台的float精度问题

梦想游戏人
 梦想游戏人
发布于 2017/09/04 20:48
字数 923
阅读 746
收藏 0

「深度学习福利」大神带你进阶工程师,立即查看>>>

帧同步的话,这个问题尤为突出,可用定点数来替代浮点数解决

 

1.....可以自己实现一套,简单的方案,就是全程用long来运算在需要转换的时候才转换

基本思想如下,在数值运算时,直接long和long 之间的运算,如果比如long和float运算,那么用函数Parse转换为long再运算,这种效率相对Fix64那种方法速度更快,并且具备可读性,在这里应该严格控制逻辑的输入和运算都是long(int64),只有在输出需要其他数据类型才转换,比如UI显示,输出到unity。。。在这个简易的定点数算法里面,非常容易溢出,原因在于用于表示小数部分的数字在参与进来的时候容易溢出,相同的数量级的数子,之所以float不会溢出是因为其用的科学计数法,而这个简易的并没有用科学计数法来表示。

public struct Decimal
{
    public const long MaxValue = long.MaxValue;
    public const long MinValue = long.MinValue;

    //转换规则,用大精度转换为小精度,比如float就用double来转换
    //对于乘除来说, 他们之间并不能直接相除 long_a*long_a / split_xxx  才是真正的结果 
    public const long SPLIT_LONG = 100000;
    public const int SPLIT_INT = 100000;
    public const float SPLIT_FLOAT = 100000.0f;
    public const double SPLIT_DOUBLE = 100000.0;
    public long value;
    public Decimal(Decimal other)
    {
        this.value = other.value;
    }
    public Decimal(long value)
    {
        this.value = value;// 默认构造不认为是定点 需要手动调用parse
    }
    public Decimal(double value)
    {
        this.value = Parse(value);
    }
    public Decimal(float value)
    {
        this.value = Parse(value);
    }
    public Decimal(int value)
    {
        this.value = Parse(value);
    }
    public static implicit operator Decimal(float value)
    {
        return new Decimal(value);
    }
    public static implicit operator Decimal(double value)
    {
        return new Decimal(value);
    }
    public static implicit operator Decimal(int value)
    {
        return new Decimal(value);
    }
    public static implicit operator Decimal(long value)
    {
        return new Decimal(value);
    }
    public static long Parse(float v)
    {
        double tmp = v;
        return (long)(tmp * SPLIT_DOUBLE);
    }
    public static long Parse(int v)
    {
        long tmp = v;
        return (long)(tmp * SPLIT_INT);
    }
    public static long Parse(double v)
    {
        double tmp = v;
        return (long)(tmp * SPLIT_DOUBLE);
    }
    public static double ToDouble(long v)
    {
        return (double)v / SPLIT_DOUBLE;
    }
    public static int ToInt(long v)
    {
        return (int)(v / SPLIT_LONG);
    }
    public static double ToFloat(long v)
    {
        return (float)ToDouble(v);
    }
    public static double ToDouble(Decimal v)
    {
        return (double)v.value / SPLIT_DOUBLE;
    }
    public static int ToInt(Decimal v)
    {
        return (int)(v.value / SPLIT_LONG);
    }
    public static double ToFloat(Decimal v)
    {
        return (float)ToDouble(v);
    }
    public static Decimal operator *(Decimal x, Decimal y)
    {
       
    }
}

 

2.....另外也有一个现成的 用long 的定点数库 Fix64

https://github.com/jjcat/FixedMath.Net/blob/master/Fix64.cs

核心算法是,用末尾32位表示小数部分
该算法的rawvalue并不直接可读,虽然是struct分配是在stack但是速度依然比较慢,可以看做是用long来实现的科学计数法,

   long xxxx=0 ;
   
        const int FRACTIONAL_PLACES = 32;
        const long ONE = 1L << FRACTIONAL_PLACES;
        xxxx += ONE * 5;
        xxxx += ONE * 2;

        Debug.LogError((float)xxxx / ONE + "        " + ONE);

输出7

 

以下是对相同数据量运算的简单测试

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using FixMath.NET;
using System.Runtime.InteropServices;

public class NewBehaviourScript : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
        //   this.GetComponent<Animator>().Play("npc_ani_100011_attack_01");
        //  this.GetComponent<Animator>().Play("npc_ani_100011_standby_01");

        long xx = 2;
        decimal bb = 2;
        float ff = 2f;
        Fix64 fx = (Fix64)2f;
        long dd = 2 * Decimal.SPLIT_LONG;
        System.Diagnostics.Stopwatch aa = new System.Diagnostics.Stopwatch();
        aa.Stop();
        aa.Reset();
        aa.Start();
        for (int i = 0; i < 999999; i++)
        {
            xx *= 2;
            xx /= 2;
        }
        Debug.LogError("long time=" + aa.ElapsedMilliseconds + "   " + xx);
        aa.Stop();
        aa.Reset();
        aa.Start();
        for (int i = 0; i < 999999; i++)
        {
            bb *= 2;
            bb /= 2;
        }
        Debug.LogError("decimal time=" + aa.ElapsedMilliseconds);

        aa.Stop();
        aa.Reset();
        aa.Start();
        for (int i = 0; i < 999999; i++)
        {
            ff *= 2f;
            ff /= 2f;
        }
        Debug.LogError("float time=" + aa.ElapsedMilliseconds + "   " + ff);
        aa.Stop();
        aa.Reset();
        aa.Start();
        for (int i = 0; i < 999999; i++)
        {
            fx = Fix64.FastMul((Fix64)2f, fx);
            fx /= (Fix64)2f;
        }
        Debug.LogError("fix64 with float time=" + aa.ElapsedMilliseconds);

        Fix64 twof = (Fix64)2f;
        aa.Stop();
        aa.Reset();
        aa.Start();
        for (int i = 0; i < 999999; i++)
        {
            fx = Fix64.FastMul(twof, fx);
            fx /= twof;
        }
        Debug.LogError("fix64 time=" + aa.ElapsedMilliseconds);


        aa.Stop();
        aa.Reset();
        aa.Start();
        for (int i = 0; i < 999999; i++)
        {
            dd *= Decimal.Parse(2f);
            dd /= Decimal.Parse(2f);
        }
        Debug.LogError("light decimal time=" + aa.ElapsedMilliseconds + "   " + Decimal.ToDouble(dd));

        /*  long xxxx=0 ;
   
          const int FRACTIONAL_PLACES = 16;
          const long ONE = 1L << FRACTIONAL_PLACES;
          xxxx += ONE * 5;
          xxxx += ONE * 2;

          Debug.LogError((float)xxxx / ONE + "        " + ONE  + "   " + ONE*ONE/ONE);*/
    }

    // Update is called once per frame
    void Update()
    {

    }
}

可见Fix64的运算速度 并不是很快

 

上一篇: go环境搭建
梦想游戏人
粉丝 44
博文 506
码字总数 201003
作品 0
成都
私信 提问
加载中
请先登录后再评论。
日志分析平台 - Kibana

Kibana 是一个为 Logstash 和 ElasticSearch 提供的日志分析的 Web 接口。可使用它对日志进行高效的搜索、可视化、分析等各种操作。 环境要求: ruby >= 1.8.7 (probably?) bundler logstash...

匿名
2013/02/13
11.7W
1
游戏开发者后端服务--OpenKit

OpenFeint 关门大吉后,OpenFeint 创始人推出了开源项目 OpenKit。OpenKit 支持Unity 3D游戏引擎,并未 iOS 和 Android 的游戏开发者提供开源 API以及存储、数据同步服务。OpenKit 目前提供對...

匿名
2013/03/11
3K
0
Java™ 编译器--Janino

Janino是一个超级小但又超级快的Java™ 编译器. 它不仅能像javac工具那样讲一组源文件编译成字节码文件,还可以对一些Java表达式,代码块,类中的文本(class body)或者内存中源文件进行编译,...

匿名
2013/04/02
4.2K
0
计算资源管理平台--Apache VCL

Apache VCL 是一个自服务的系统,为最终用户提供专用计算环境的远程访问环境。典型的使用场景是数据中心,也可以是物理刀片服务器、传统机架服务器或者虚拟机。VCL 也可以提供独立机器的代理...

匿名
2013/01/04
2.6K
0
复杂网络分析平台--Gephi

Gephi是一款开源的交互式的复杂网络分析平台。它支持Windows, Mac OS X以及Linux等环境。主要功能包括: 网络布局:提供了超过10种不同的布局算法 网络社区分析和分类 网络属性计算 动态网络...

匿名
2013/04/22
2.6W
0

没有更多内容

加载失败,请刷新页面

加载更多

Hacker News 简讯 2020-08-15

最后更新时间: 2020-08-15 04:01 Welders set off Beirut blast while securing explosives - (maritime-executive.com) 焊工在固定炸药的同时引爆了贝鲁特爆炸 得分:215 | 评论:209 Factor......

FalconChen
今天
24
0
OSChina 周六乱弹 —— 老椅小猫秋乡梦 梦里石台堆小鱼

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @小小编辑 :《MOM》- 蜡笔小心 《MOM》- 蜡笔小心 手机党少年们想听歌,请使劲儿戳(这里) @狄工 :腾讯又在裁员了,35岁以上清退,抖音看到...

小小编辑
今天
61
1
构建高性能队列,你不得不知道的底层知识!

前言 本文收录于专辑:http://dwz.win/HjK,点击解锁更多数据结构与算法的知识。 你好,我是彤哥。 上一节,我们一起学习了如何将递归改写为非递归,其中,用到的数据结构主要是栈。 栈和队列...

彤哥读源码
今天
17
0
Anaconda下安装keras和tensorflow

Anaconda下安装keras和tensorflow 一、下载并安装Anaconda: Anaconda下载 安装步骤: 如果是多用户操作系统选择All Users,单用户选择Just Me 选择合适的安装路径 然后勾选这个,自动配置环境...

Atlantis-Brook
今天
15
0
滴滴ElasticSearch千万级TPS写入性能翻倍技术剖析

桔妹导读:滴滴ElasticSearch平台承接了公司内部所有使用ElasticSearch的业务,包括核心搜索、RDS从库、日志检索、安全数据分析、指标数据分析等等。平台规模达到了3000+节点,5PB 的数据存储...

滴滴技术
今天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部