文档章节

Unity net平台的float精度问题

梦想游戏人
 梦想游戏人
发布于 2017/09/04 20:48
字数 923
阅读 63
收藏 0
点赞 0
评论 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的运算速度 并不是很快

 

© 著作权归作者所有

共有 人打赏支持
梦想游戏人
粉丝 34
博文 402
码字总数 115594
作品 0
成都
【Unity】多线程和主线程交互使用类——Loom工具分享(转载)

作者:D.S.Qiu 原文:Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享 熟悉Unity的developer都知道在Unity中的线程不能使用Unity的对象,但可以使用Unity的值类型变...

何三思 ⋅ 04/12 ⋅ 0

Unity网页数据交互基本原理

1. u3d是一个3D游戏引擎由于和编辑器集成在一起 所以也可以理解为一个制作/开发平台 2. u3d使用javascript C#作为核心脚本语言 来驱动整个游戏引擎 3. 平台可以发布为Exe执行文件或者打包为供...

qq_30279553 ⋅ 04/22 ⋅ 0

将成型的iOS工程嵌入到u3d工程中

一、合并iOS工程和u3d工程 1、一个U3d导出的Xcode工程Unity-iPhone,单独编译运行OK 2、一个iOS工程ARHere,单独编译运行OK 3、打开终端cd 到Unity-iPhone文件夹,vim Podfile,把ARHere的内...

朝雨晚风 ⋅ 2016/11/29 ⋅ 0

Unite Beijing 2018|行业应用精彩议题曝光

我们不久之前为大家提前曝光了部分大会精彩技术议题,引起了大家的广泛关注。作为世界顶尖的内容创作引擎,Unity不仅仅可用于跨平台的游戏开发,越来越多的开发者将Unity运用到制造业,汽车,...

weixin_41849687 ⋅ 04/20 ⋅ 0

HoloLens开发——C++ DLL封装及在win32、Unity、AR眼镜中调用情况

一、C++ Dll基础了解 动态链接库(dll)比较好的介绍在孙鑫《VC++深入详解》第十九章动态链接库中有详细介绍。主要涉及以下问题: 1.静态链接库与动态链接库的区别 https://blog.csdn.net/za...

haitianyunlan ⋅ 05/09 ⋅ 0

Substance与PBR工作流总结

PBR介绍 PBR即基于物理的渲染,是一套尝试基于真实世界光照物理模型的渲染技术合集,使用了一种更符合物理学规律的方式来模拟光线,达到更真实的渲染效果,而且可以直接通过物理参数来直观地...

leohijack ⋅ 05/11 ⋅ 0

【AR】在Unity中开始使用Vuforia(1)

原 目录 在Unity中开始使用Vuforia Vuforia在统一 关于Vuforia 安装Vuforia 创建一个新的Unity项目 Vuforia游戏对象 在您的项目中激活Vuforia 访问Unity中的Vuforia功能 将目标添加到您的场景...

lichong951 ⋅ 06/11 ⋅ 0

引领前沿科技-Unite Beijing 2018核心主题抢先知

5月11日-13日,Unite Beijing 2018大会将于北京国家会议中心举办!作为开发者的年度盛会,我们将邀请来自全球的Unity技术达人和行业精英,为大家带来超过70场主题多元的技术课程,包括聚焦U...

weixin_41849687 ⋅ 04/20 ⋅ 0

Shader笔记(Pass相关)

Subshader整体结构: Tags和CommonState主要运用与设定,Pass运用于算法实现。 Pass作用:控制被渲染的几何体对象。 Tags: light map? 好像是光照在三维引擎打好后 生成的贴图。 ShadowCast...

vermouthstx ⋅ 04/13 ⋅ 0

Unity Memory 内存 官方文档笔记

本文档主要是对Unity官方教程的个人理解与总结(其实以翻译记录为主:>) 仅作为个人学习使用,不得作为商业用途,欢迎转载,并请注明出处。 文章中涉及到的操作都是基于 Unity2017.3版本 参...

cangod ⋅ 04/18 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用SQL命令查看Mysql数据库大小

要想知道每个数据库的大小的话,步骤如下: 1、进入information_schema 数据库(存放了其他的数据库的信息) use information_schema; 2、查询所有数据的大小: select concat(round(sum(da...

源哥L ⋅ 38分钟前 ⋅ 0

两个小实验简单介绍@Scope("prototype")

实验一 首先有如下代码(其中@RestController的作用相当于@Controller+@Responsebody,可忽略) @RestController//@Scope("prototype")public class TestController { @RequestMap...

kalnkaya ⋅ 43分钟前 ⋅ 0

php-fpm的pool&php-fpm慢执行日志&open_basedir&php-fpm进程管理

12.21 php-fpm的pool pool是PHP-fpm的资源池,如果多个站点共用一个pool,则可能造成资源池中的资源耗尽,最终访问网站时出现502。 为了解决上述问题,我们可以配置多个pool,不同的站点使用...

影夜Linux ⋅ 52分钟前 ⋅ 0

微服务 WildFly Swarm 管理

Expose Application Metrics and Information 要公开关于我们的微服务的有用信息,我们需要做的就是将监视器模块添加到我们的pom.xml中: 这将使在管理和监视功能得到实现。从监控角度来看,...

woshixin ⋅ 52分钟前 ⋅ 0

java连接 mongo伪集群部署遇到的坑

部署mongo伪集群 #创建mongo数据存放文件地址mkdir -p /usr/local/config1/datamkdir -p /usr/local/config2/data mkdir -p /usr/local/config3/data mkdir -p /usr/local/config1/l......

努力爬坑人 ⋅ 53分钟前 ⋅ 0

React Native & Weex 区别

JS引擎 Weex使用V8, React native使用JSCore JS开发框架 ( Js Framework ) Weex基于vue.js(2W+ star)。小巧轻量的前端开发框架,组件化,数据绑定,2.0引入virtual dom。 ReactNative使用...

东东笔记 ⋅ 今天 ⋅ 1

UIkit 分页组件动态加载简单实现

1. 问题描述 使用过UIkit分页组件的都清楚,UIkit的分页不能动态刷新数据,也就是不能在点击下一页的时候,动态从后台加载数据,并且刷新页数以及该页数上的数据,下面是一个简单实现,没有做...

影狼 ⋅ 今天 ⋅ 0

Mobx入门之三:Provider && inject

上一节中<App/>组件传递状态temperatures给children -- <TemperatureInput />,如果组建是一个tree, 那么属性的传递则会非常繁琐。redux使用Provider给子组件提供store, connect将子组件和s...

pengqinmm ⋅ 今天 ⋅ 0

魔兽世界 7.0版本 S23/S24/S25全职业普通+精锐套

  死亡骑士   (联盟)   (部落)   (精锐)   恶魔猎手   (联盟)   (部落)   (精锐)   德鲁伊   (联盟)   (部落)   (精锐)   猎人   (联盟) ...

wangchen1999 ⋅ 今天 ⋅ 0

maven顶级pom和子pom的版本号批量修改

当一个版本发布,新起一个版本时,我们只需要手动修改一下项目中pom.xml的版本号就可以了。但是如果这个maven项目有很多的子模块项目,那么一个个手动的去改就显得费时费力又繁琐了。还好,m...

ArlenXu ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部