<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Game-Dev on NicoLabs</title>
		<link>http://blog.hellonico.info/zh/tags/game-dev/</link>
		<description>Recent content in Game-Dev on NicoLabs</description>
		<generator>Hugo</generator>
		<language>zh</language>
		
		
		
		
			<lastBuildDate>Sun, 28 Jun 2026 11:30:00 +0900</lastBuildDate>
		
			<atom:link href="http://blog.hellonico.info/zh/tags/game-dev/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>针对Coni原生Float32数组的硬核混沌测试</title>
				<link>http://blog.hellonico.info/zh/posts/coni/float32-chaos-testing/</link>
				<pubDate>Sun, 28 Jun 2026 11:30:00 +0900</pubDate>
				<guid>http://blog.hellonico.info/zh/posts/coni/float32-chaos-testing/</guid>
				<description>&lt;p&gt;当您在浏览器中构建高性能应用程序时，JavaScript通用的 &lt;code&gt;Number&lt;/code&gt; 类型通常是不够的。您需要原始的、连续的内存数组。在Coni WASM中，我们在计算最密集的应用程序上严重依赖原生的WebAssembly &lt;code&gt;float32&lt;/code&gt; 数组。&lt;/p&gt;&#xA;&lt;h3 id=&#34;float32在coni中到底用在哪里&#34;&gt;Float32在Coni中到底用在哪里？&lt;/h3&gt;&#xA;&lt;p&gt;原生 &lt;code&gt;float32&lt;/code&gt; 数组（&lt;code&gt;make-float32-array&lt;/code&gt;、&lt;code&gt;f32-set!&lt;/code&gt;、&lt;code&gt;f32-get&lt;/code&gt;）是Coni性能层的绝对主干。您会发现它们驱动着：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;WebGL几何体:&lt;/strong&gt; 在我们的 &lt;a href=&#34;https://coni-lang.org/wasm-apps/apps/deep-focus-webgl/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreffer &#34;&gt;&lt;code&gt;deep-focus-webgl&lt;/code&gt;&lt;/a&gt; 应用中，我们使用 &lt;code&gt;float32&lt;/code&gt; 数组在原生层面通过数学方式塑造一个拥有80,000个顶点的大脑矩阵（240,000个浮点数！），然后通过 &lt;code&gt;js/float32-buffer&lt;/code&gt; 将其一次性发送给GPU。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;游戏引擎粒子系统:&lt;/strong&gt; 对于像 &lt;code&gt;flappy-bird&lt;/code&gt; 或 &lt;code&gt;neon-boids&lt;/code&gt; 这样的游戏，并行的 &lt;code&gt;float32&lt;/code&gt; 数组无需垃圾回收的停顿，即可跟踪数以千计的X/Y坐标、速度和生命周期。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;原始DSP音频:&lt;/strong&gt; 我们的 &lt;code&gt;sound-nodes&lt;/code&gt; 合成器在将复杂的脉冲响应和噪声波形映射到WebAudio通道之前，使用 &lt;code&gt;float32&lt;/code&gt; 数组在原生层面计算它们。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;错误所在类型强制转换与-f64reinterpret_i64&#34;&gt;错误所在：类型强制转换与 &lt;code&gt;f64.reinterpret_i64&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;p&gt;因为这些数组极其关键，它们中的任何错误都将是灾难性的。最近，我们发现了一个问题：将一个精确的整数（如 &lt;code&gt;150&lt;/code&gt;）传入 &lt;code&gt;f32-set!&lt;/code&gt; 时，会莫名其妙地产生 &lt;code&gt;0.0&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;到底发生了什么？在较早版本的WASM编译器中，将整数传递给浮点数setter会导致编译器错误地使用 &lt;code&gt;f64.reinterpret_i64&lt;/code&gt; 来解释这些位，从而完全扰乱了底层的值。&lt;/p&gt;&#xA;&lt;h3 id=&#34;解决方案float32混沌测试-chaos-testing&#34;&gt;解决方案：Float32混沌测试 (Chaos Testing)&lt;/h3&gt;&#xA;&lt;p&gt;我们修补了编译器，以便在插入内存之前将整数正确地强制转换为浮点数，但我们需要一个保证，确保它永远不会再次退化。于是，&lt;strong&gt;混沌测试&lt;/strong&gt;登场了。&lt;/p&gt;&#xA;&lt;p&gt;在新的 &lt;code&gt;float32_coercion_test.coni&lt;/code&gt; 测试套件中，我们构建了一个硬核的混沌测试。我们不是仅仅测试几个顺利通过的数字，而是分配了一个巨大的数组，并用确定性的、伪随机的循环来猛烈敲击它。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;deftest&lt;/span&gt; test-f32-chaos&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;针对float32数组边界和类型转换的硬核混沌测试。&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#66d9ef&#34;&gt;let &lt;/span&gt;[size &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        arr (&lt;span style=&#34;color:#a6e22e&#34;&gt;make-float32-array&lt;/span&gt; size)]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#66d9ef&#34;&gt;loop &lt;/span&gt;[i &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#66d9ef&#34;&gt;if &lt;/span&gt;(&amp;lt; i size)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#66d9ef&#34;&gt;let &lt;/span&gt;[&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#75715e&#34;&gt;;; 混合生成极端边缘用例：&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          val (&lt;span style=&#34;color:#66d9ef&#34;&gt;if &lt;/span&gt;(= (&lt;span style=&#34;color:#a6e22e&#34;&gt;mod&lt;/span&gt; i &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) (- &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; i)                   &lt;span style=&#34;color:#75715e&#34;&gt;;; 负整数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (&lt;span style=&#34;color:#66d9ef&#34;&gt;if &lt;/span&gt;(= (&lt;span style=&#34;color:#a6e22e&#34;&gt;mod&lt;/span&gt; i &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) (* i &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;)             &lt;span style=&#34;color:#75715e&#34;&gt;;; 大正整数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  (&lt;span style=&#34;color:#66d9ef&#34;&gt;if &lt;/span&gt;(= (&lt;span style=&#34;color:#a6e22e&#34;&gt;mod&lt;/span&gt; i &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) (+ i &lt;span style=&#34;color:#ae81ff&#34;&gt;0.5&lt;/span&gt;)             &lt;span style=&#34;color:#75715e&#34;&gt;;; 精确的float32小数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)))                                    &lt;span style=&#34;color:#75715e&#34;&gt;;; 零（整数）&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#a6e22e&#34;&gt;f32-set!&lt;/span&gt; arr i val)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          (&lt;span style=&#34;color:#a6e22e&#34;&gt;recur&lt;/span&gt; (+ i &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        nil))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;;; ... 验证循环 ...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过故意将极端正整数、负边界值、纯零和带有小数的浮点数这种残酷的混合物向 &lt;code&gt;f32-set!&lt;/code&gt; 函数抛出1,000次，我们保证了能避免WASM陷阱（traps），并且类型强制转换变得坚不可摧。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
