0

标准化 Vector3 对象的两种方法;通过调用 Vector3.Normalize() 和另一个从头开始规范化:

class Tester {
    static Vector3 NormalizeVector(Vector3 v)
    {
        float l = v.Length();
        return new Vector3(v.X / l, v.Y / l, v.Z / l);
    }

    public static void Main(string[] args)
    {
        Vector3 v = new Vector3(0.0f, 0.0f, 7.0f);
        Vector3 v2 = NormalizeVector(v);
        Debug.WriteLine(v2.ToString());
        v.Normalize();
        Debug.WriteLine(v.ToString());
    }
}

上面的代码产生了这个:

X: 0
Y: 0
Z: 1

X: 0
Y: 0
Z: 0.9999999

为什么?

(奖励积分:为什么是我?)

4

5 回答 5

2

看看他们是如何实现它的(例如在 asm 中)。

也许他们想要更快并产生类似的东西:

 l = 1 / v.length();
 return new Vector3(v.X * l, v.Y * l, v.Z * l);

用 2 个除法对 3 个乘法进行交易(因为他们认为 mults 比 divs 更快(这对于现代 fpus 来说通常是无效的))。这引入了一个级别的操作,因此精度较低。

这将是经常被引用的“过早优化”。

于 2008-11-27T08:54:53.733 回答
0

不要在意这个。使用浮点数时总是会出现一些错误。如果您很好奇,请尝试更改为双倍,看看是否仍然会发生这种情况。

于 2008-11-27T08:39:11.407 回答
0

您在这里有一个关于浮点数的字符串格式的有趣讨论。

仅供参考:

您的数字需要 24 位来表示,这意味着您正在用完一个浮点数的整个尾数(23 位 + 1 个隐含位)。
Single.ToString() 最终是由一个原生函数实现的,所以我无法确定发生了什么,但我的猜测是它使用最后一位数字来舍入整个尾数。
这背后的原因可能是你经常得到不能用二进制精确表示的数字,所以你会得到一个很长的尾数;例如,0.01 在内部表示为 0.00999... 你可以通过以下方式看到:

float f = 0.01f;
Console.WriteLine ("{0:G}", f);
Console.WriteLine ("{0:G}", (double) f);

通过在第七位四舍五入,您将得到“0.01”,这是您所期望的。

正如您已经看到的,对于上面所见,只有 7 位数字的数字不会显示此问题。

需要说明的是:仅当您将数字转换为字符串时才会进行舍入:您的计算(如果有)将使用所有可用位。

浮点数的外部精度为 7 位(内部为 9 位),因此如果超过该精度,则舍入(具有潜在的怪癖)是自动的。
如果您将浮点数降低到 7 位(例如,向左 1,向右 6),那么它会起作用并且字符串转换也会起作用。

至于奖励积分:

为什么你 ?因为这段代码“渴望打击你”。
(火神......吹......好吧。最蹩脚的。平底船。曾经)

于 2008-11-27T08:49:32.823 回答
0

使用浮点数时您应该预料到这一点,其基本原因是计算机以二进制方式处理,而这并不完全映射到十进制。

对于不同基数之间问题的直观示例,请考虑分数 1/3。它不能用十进制精确表示(它是 0.333333 .....),但可以用三进制表示(如 0.1)。

通常,这些问题在使用双精度时不太明显,但以计算成本为代价(要操作的位数翻倍)。然而,鉴于浮点精度足以让人类登上月球,那么你真的不应该着迷:-)

这些问题有点像计算机理论 101(与编程 101 相反——你显然远远超出了这一点),如果你走向 Direct X 代码,类似的事情会经常出现,我建议这可能是个好主意拿起一本基本的计算机理论书并快速阅读。

于 2008-11-27T08:50:02.417 回答
0

如果您的代码因微小的浮点舍入错误而损坏,那么恐怕您需要修复它,因为它们只是生活中的事实。

于 2008-11-27T09:01:14.233 回答