我写了一个小型的软件合成的。
为进一步优化绩效测量我的应用程序与鲨鱼发现我失去了很多时间在浮/SInt16转换。
所以我改写了一份得到周围的转换通过预先计算的查询表,返回"准备使用的"SInt16样本。这一工作的现为止。
目前,我试图重写某些过滤器和我的起点触发票的信封的实施只使用整数的算术但是我可以使用一些提示如何执行的乘法/司没有浮动。
我针对的 iPhone规范格式:

  • 拷贝
  • 16位整数的样本

什么是好的做法适用的幅度到我最后的样品没有使用一个浮起来?

编辑:
我唯一想通了迄今为止是的,我可以划分的权力,2通过右转变我现在的样品。

inBuffer[frame] = wavetable[i % cycleLengthInSamples] >> 4;

但是我不能想到的任何优雅的方式来创建一个光滑的起点触发票的信封用的。

Edit2: 谢谢你的伟大的答案!
我目前的方法:

  • 带来我所有的起点触发票的信封值 进入正SInt16范围
  • 乘与目前的价值从波表(商店中间体作为SInt32)
  • 移的结果,16至右

这似乎是工作:)

有帮助吗?

解决方案

固定点是好的,因为在这种情况下你使用的16位。最简单的方法是乘以一个功率为10根据精密的需要。如果你可以使用的32位整数作为中间,你应该能够得到体面的精确度。在结束你可以转换回到16位整数,四舍五入或截断为你喜欢。

编辑:你想要转移到左边,使该值更大。商店的结果转变的一种类型更精确(32或64位取决于你需要什么). 简单的转移不会工作如果您使用的签名类型

看如果你乘以或除以两个固定点数。乘风正(a*n)*(bn)和只有一个bn^2,而不是一个bn.司(an)/(bn)其是(a/b),而不是((an)/b)。这就是为什么我建议用权力的10,使得它很容易找到你的错误如果你不熟悉的固定点。

当你完成你的计算,转移回有权获得回到16位int。如果你想要得花哨,你也可以做四舍五入之前移。

我建议你做一些阅读如果你真的有兴趣在实施有效的固定点。 http://www.digitalsignallabs.com/fp.pdf

其他提示

答案 这个这么问题 是相当全面的执行情况。这里是多一点的解释比我见过的有:

一个方法是迫使所有你的号码进入一个范围,说[为-1.0,1.0).然后你这些数字地图进入范围[-2^15,(2^15)-1].例如,

Half = round(0.5*32768); //16384
Third = round((1.0/3.0)*32768); //10923

当你乘以这两个数字你

Temp = Half*Third; //178962432
Result = Temp/32768; //5461 = round(1.0/6.0)*32768

除32768在最后一行中被点 Patros 做了大约将需要额外扩展的步骤。这使得更有意义,如果你写的2^N定标明确的:

x1 = x1Float*(2^15);
x2 = x2Float*(2^15);
Temp = x1Float*x2Float*(2^15)*(2^15);
Result = Temp/(2^15); //get back to 2^N scaling

这样的算术运算。实施,请注意,乘两16位整数需要一个32位的结果,使温度应该是32位。此外,32768不可表示在16位变量,所以要知道,编译器将使32位immediates.和如你已经指出,你可以转移到乘/鸿沟,通过权力2以你可以写

N = 15;
SInt16 x1 = round(x1Float * (1 << N));
SInt16 x2 = round(x2Float * (1 << N));
SInt32 Temp = x1*x2;
Result = (SInt16)(Temp >> N);
FloatResult = ((double)Result)/(1 << N);

但是,假设[-1,1)不是正确的范围?如果你宁愿限制你的号码,说,[-4.0,4.0),可以使用N=13.然后你有1号位,两位前二点,13之后。这些被称为1.15和3.13固定点的分类。你贸易的精密中的部分空间。

加和减的分类工作的只要你看出来饱和。为鸿沟,作为Patros说,比例实际上取消。所以你必须做

Quotient = (x1/x2) << N;

或者,维护精密

Quotient = (SInt16)(((SInt32)x1 << N)/x2); //x1 << N needs wide storage

乘以及分割的整体数字的正常工作。例如,除以6你可以简单地写

Quotient = x1/6; //equivalent to x1Float*(2^15)/6, stays scaled

和在的情况下分割的一个功率为2,

Quotient = x1 >> 3; //divides by 8, can't do x1 << -3 as Patros pointed out

加和减整体数字,但是,不能工作的天真。你要先看看,如果整合在你的x。y型,使本等同的分类,并继续进行。

我希望这可以帮助的想法,看看中的代码,其他问题清洁的方式实现的。

看看这个页面,介绍了快速的乘法运算。

http://www.newton.dep.anl.gov/askasci/math99/math99199.htm

在一般情况下,说你将会利用一个签署16.16固定点表示。因此,一个32位整数将已签署的16位整数部分和16位小数部分。然后我不知道这是什么语言中使用的iPhone发展(目标-C或许?), 但是这个实例是在C:

#include <stdint.h>

typedef fixed16q16_t int32_t ;
#define FIXED16Q16_SCALE 1 << 16 ;

fixed16q16_t mult16q16( fixed16q16_t a, fixed16q16_t b )
{
    return (a * b) / FIXED16Q16_SCALE ;
}

fixed16q16_t div16q16( fixed16q16_t a, fixed16q16_t b )
{
    return (a * FIXED16Q16_SCALE) / b ;
}

请注意,上述是一个简单的执行情况,并提供保护,从算术溢出。例如在div16q16()我多个前的划分,以维持的精确度,但这取决于操作的操作可能会溢出。你可能会使用一64位中间来克服这一点。还的鸿沟一直轮下来,因为它使用了整数部门。这提供了最好的性能,但可能会影响的精密的迭代计算。修复是简单的,但是增加的开销。

注意,当时乘以或除以恒定的功率的两个,大多数编纂者会发现普通优化和使用的转变。然而C会不定义的行为的一个右转移的负面签署整数,所以我必须离开它的编译工作出于安全和可移植性。YMV在任何一种语言所使用。

在一个面向对象的语言、fixed16q16_t自然会是一个候选人类与操作者负载过重,因此您可以使用它就像一个正常运算的类型。

你可能会发现它很有用之间的转换种类型:

double fixed16q16_to_double( fixed16q16_t fix )
{
    return (double)fix / FIXED16Q16_SCALE ;
}

int fixed16q16_to_int( fixed16q16_t fix )
{
    // Note this rounds to nearest rather than truncates
    return ((fix + FIXED16Q16_SCALE/2)) / FIXED16Q16_SCALE ;
}

fixed16q16_t int_to_fixed16q16( int i )
{
    return i * FIXED16Q16_SCALE ;
}

fixed16q16_t double_to_fixed16q16( double d )
{
    return (int)(d * FIXED16Q16_SCALE) ;
}

这是基础,能够获得更加复杂,并添加trig和其他数学的功能。

固定加法和减法的工作与内建和运营商及其变体。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top