如何检查一个范围内的值是否是另一个范围内的值的倍数

How to check if a value within a range is multiple of a value from another range?

本文关键字:范围内 是否是 另一个 何检查 检查 一个      更新时间:2023-10-16

假设我有一个系统,将 8820 个值分成 96 个值,使用银行家舍入(称它们为 pulse (。公式为:

pulse = BankerRound(8820 * i/96), with i[0,96[

因此,这是脉冲列表:

0
92
184
276
368
459
551
643
735
827
919
1011
1102
1194
1286
1378
1470
1562
1654
1746
1838
1929
2021
2113
2205
2297
2389
2481
2572
2664
2756
2848
2940
3032
3124
3216
3308
3399
3491
3583
3675
3767
3859
3951
4042
4134
4226
4318
4410
4502
4594
4686
4778
4869
4961
5053
5145
5237
5329
5421
5512
5604
5696
5788
5880
5972
6064
6156
6248
6339
6431
6523
6615
6707
6799
6891
6982
7074
7166
7258
7350
7442
7534
7626
7718
7809
7901
7993
8085
8177
8269
8361
8452
8544
8636
8728

现在,假设系统没有直接向我发送这些脉冲。相反,它会在第 8820 次发送这些脉冲(称它们为 tick(:

tick = value * 1/8820

我得到的刻度列表变成了:

0
0.010430839
0.020861678
0.031292517
0.041723356
0.052040816
0.062471655
0.072902494
0.083333333
0.093764172
0.104195011
0.11462585
0.124943311
0.13537415
0.145804989
0.156235828
0.166666667
0.177097506
0.187528345
0.197959184
0.208390023
0.218707483
0.229138322
0.239569161
0.25
0.260430839
0.270861678
0.281292517
0.291609977
0.302040816
0.312471655
0.322902494
0.333333333
0.343764172
0.354195011
0.36462585
0.375056689
0.38537415
0.395804989
0.406235828
0.416666667
0.427097506
0.437528345
0.447959184
0.458276644
0.468707483
0.479138322
0.489569161
0.5
0.510430839
0.520861678
0.531292517
0.541723356
0.552040816
0.562471655
0.572902494
0.583333333
0.593764172
0.604195011
0.61462585
0.624943311
0.63537415
0.645804989
0.656235828
0.666666667
0.677097506
0.687528345
0.697959184
0.708390023
0.718707483
0.729138322
0.739569161
0.75
0.760430839
0.770861678
0.781292517
0.791609977
0.802040816
0.812471655
0.822902494
0.833333333
0.843764172
0.854195011
0.86462585
0.875056689
0.88537415
0.895804989
0.906235828
0.916666667
0.927097506
0.937528345
0.947959184
0.958276644
0.968707483
0.979138322
0.989569161

不幸的是,在这些刻度之间,它也fake ticks发送给我的,这不是原始pulses的倍增。如0,029024943,它是256的乘数,不在脉冲列表中。

如何从此列表中找到哪些即时报价valid,哪些fake?在此过程中,我没有可以比较的脉搏列表,因为在此期间8820会发生变化,所以我没有可以逐步比较的列表。我需要从每次迭代时的即时报价中推断出它。

最好的数学方法是什么?也许推理只在滴答声而不是脉搏中。

我想在最近的整数脉冲和上一个/下一个刻度之间找到更近的误差。这里C++:

double pulse = tick * 96.;
double prevpulse = (tick - 1/8820.) * 96.;
double nextpulse = (tick + 1/8820.) * 96.;
int pulseRounded=round(pulse);
int buffer=lrint(tick * 8820.);
double pulseABS = abs(pulse - pulseRounded);
double prevpulseABS = abs(prevpulse - pulseRounded);
double nextpulseABS = abs(nextpulse - pulseRounded);
if (nextpulseABS > pulseABS && prevpulseABS > pulseABS) {
    // is pulse
} 

但例如,即时报价0.0417234(脉冲368(失败,因为前一个即时报价误差似乎比它更接近:prevpulseABS误差(0.00543795(小于pulseABS误差(0.0054464(。

那是因为这个比较并不关心我猜的四舍五入。

新帖子:

好。根据我现在的理解,这是我修改后的答案。

您拥有构建良好值列表所需的信息。每次切换到新曲目时:

vector<double> good_list;
good_list.reserve(96);
for(int i = 0; i < 96; i++)
    good_list.push_back(BankerRound(8820.0 * i / 96.0) / 8820.0);

然后,每次要验证输入时:

auto iter = find(good_list.begin(), good_list.end(), input);
if(iter != good_list.end()) //It's a match!
    cout << "Happy days! It's a match!" << endl;
else
    cout << "Oh bother. It's not a match." << endl;

在数学上确定正确脉冲的问题是BankerRound((函数,它会导致您输入的值越高,误差就会越来越大。然后你需要一个公式的公式,这就从我的驾驶室里出来了。或者,您可以跟踪连续值之间的差异。它们中的大多数都是一样的。您只需要在两个可能的错误之间进行检查。但是,如果您可以跳过轨道或在一条轨道上跳来跳去,那就会分崩离析。

旧帖子:

如果我正确理解了这个问题,你得到的唯一信息应该是(p/v = y(的形式,你知道"y"(这是你从设备获得的即时报价列表中的每个元素(,你知道"p"是脉冲,"v"是每拍值,但你不知道它们是什么。因此,从您的帖子中提取一个数据点,您可能会有这样的等式:

P/V = 0.010430839

到目前为止,在您使用的所有示例中,"v"是 8820,但据我了解,该值不是一个保证常量。接下来的问题是:在开始获取所有这些十进制值之前,您是否有办法确定"v"是什么?如果你这样做,你可以用数学计算出最小的误差是多少(1/v(,然后取你的十进制信息,乘以"v",四舍五入到最接近的整数,并检查其舍入形式和非舍入形式之间的差异是否落在计算误差的范围内,如下所示:

double input; //let input be elements in your list of doubles, such as 0.010430839
double allowed_error = 1.0 / values_per_beat;
double proposed = input * values_per_beat;
double rounded = std::round(proposed);
if(abs(rounded - proposed) < allowed_error){cout << "It's good!" << endl;}

但是,如果您无法提前确定values_per_beat,那么这将成为统计问题。您必须积累足够的数据样本,删除异常值(与标准不同的少数异常值(并使用该数据。但是这种方法不会是实时的,考虑到您一直在使用的术语(每拍值,bpm,值44100(,听起来实时可能是您所追求的。

玩弄 Excel,我认为您想乘以(应该是(整数,而不是寻找最接近的脉冲。

Tick                Pulse                   i   Error                           OK
                Tick*8820       Pulse*96/8820   ABS( i - INT( i+0.05 ) )    Error < 0.01
------------    ------------    -------------   ------------------------    ------------
0.029024943     255.9999973     2.786394528     0.786394528                 FALSE
0.0417234       368.000388      4.0054464       0.0054464                   TRUE
0                 0             0               0                           TRUE
0.010430839      91.99999998    1.001360544     0.001360544                 TRUE
0.020861678     184             2.002721088     0.002721088                 TRUE
0.031292517     275.9999999     3.004081632     0.004081632                 TRUE
0.041723356     367.9999999     4.005442176     0.005442176                 TRUE
0.052040816     458.9999971     4.995918336     0.004081664                 TRUE
0.062471655     550.9999971     5.99727888      0.00272112                  TRUE
0.072902494     642.9999971     6.998639424     0.001360576                 TRUE
0.083333333     734.9999971     7.999999968     3.2E-08                     TRUE

该表显示了您的两个"问题"情况(真正的错误值 256,您的代码出错的值 368(,后跟前几个"好"值。

如果两个8820同时变化,那么显然它们会抵消,i只会Tick*96

Error项是计算i和最接近的整数之间的差;如果小于0.01,则它是一个"好"值。

注意:0.050.01值的选择有些随意(即基于数字的启发性首次猜测(:根据需要进行调整。 虽然我只显示了前几行,但您给出的所有 96 个"良好"值都显示为 TRUE。

代码(完全未经测试(如下所示:

double pulse = tick * 8820.0 ;
double i = pulse * 96.0 / 8820.0 ;
double error = abs( i - floor( i + 0.05 ) ) ;
if( error < 0.05 ) {
    // is pulse
}

我假设你在for循环中初始化脉冲,使用int i作为循环变量;那么问题是这一行:

BankerRound(8820 * i/96);

8820 * i / 96是一个全整数运算,结果再次是整数,切断余数(所以实际上,总是已经四舍五入到零(,BankerRound 实际上没有什么可舍入的了。试试这个:

BankerRound(8820 * i / 96.0);

如果您尝试计算上一个脉冲和下一个脉冲,则会出现同样的问题,因为您实际上减去并加 0(同样,1/8820都是整数并导致 0(。

编辑:

从我

从公报中读到的内容来看,"系统"并不像我之前假设的那样是不可修改的。实际上,它以 n

/96.0、n &#x220a [0, 96( 的形式  计算 N 中的
即时报价但是,包括某种内部舍入似乎与采样频率无关,因此与 n/96.0 的真实值存在一些差异,并且乘以 96 的刻度不能准确提供 [0, 96( 中的整数值(感谢 KarstenKoop(。而且一些交付的样品根本无效......

因此,任务是检测 tick * 96 是否足够接近整数值以被接受为有效。

所以我们需要检查:

double value = tick * 96.0;
bool isValid
    =  value - floor(value) < threshold
    || ceil(value) - value  < threshold;

具有一些适当定义的阈值。假设这些值确实计算为

double tick = round(8820*i/96.0)/8820.0;

那么最大偏差将略大于 0.00544(有关更精确的值,请参见下文(,阈值的大小为 0.006、0.0055、0.00545、...可能是一个选择。

舍入可能是内部使用的传感器值位数的问题(如果我们有 13 位可用,则刻度实际上可能计算为 floor(8192 * i / 96.0) / 8192.0 8192 1 << 13 &ndash 和整数除法的下限会计;只是一个猜测......

最大偏差的精确值,以 8820 为因子,精确到可以用双精度表示,为:
0.005442176870751325168384937569499901580810546875

乘以 96

实际上不是必需的,您可以直接与阈值除以 96 进行比较,即:
0.0000566893424036596371706764330156147480010986328125