Last active
June 30, 2021 08:39
-
-
Save AliceLR/42dcea80facac4f5efc76f34a36b8fc3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if 0 | |
g++ -O3 -g -Wall -Wextra anticlick.cpp -oanticlick | |
exit 0 | |
#endif | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <chrono> | |
#include <vector> | |
#define EXEC_TIMES 100000 | |
#define BUFFERSIZE 1024 | |
static void get_smpl(int32_t &left, int32_t &right) | |
{ | |
static int16_t smpl_left = (rand() - (RAND_MAX / 2)); | |
static int16_t smpl_right = (rand() - (RAND_MAX / 2)); | |
if(smpl_left >= -8192 && smpl_left <= 8192) | |
smpl_left = (int16_t)(60659); | |
if(smpl_right >= -8192 && smpl_right <= 8192) | |
smpl_right = (int16_t)(-60659); | |
left = smpl_left; | |
right = smpl_right; | |
} | |
static void old_algorithm(int32_t *buf, int count) | |
{ | |
int32_t left, right; | |
get_smpl(left, right); | |
int max_x2 = count * count; | |
while(count--) | |
{ | |
*buf++ += (count * (left >> 10) / max_x2 * count) << 10; | |
*buf++ += (count * (right >> 10) / max_x2 * count) << 10; | |
} | |
} | |
static void floating_point(int32_t *buf, int count) | |
{ | |
int32_t left, right; | |
get_smpl(left, right); | |
float max_x2 = (float)count * (float)count; | |
while(count--) | |
{ | |
float coef = (float)count * (float)count / max_x2; | |
*buf++ += (int32_t)(left * coef); | |
*buf++ += (int32_t)(right * coef); | |
} | |
} | |
static void double_floating_point(int32_t *buf, int count) | |
{ | |
int32_t left, right; | |
get_smpl(left, right); | |
double max_x2 = (double)count * (double)count; | |
while(count--) | |
{ | |
double coef = (double)count * (double)count / max_x2; | |
*buf++ += (int32_t)(left * coef); | |
*buf++ += (int32_t)(right * coef); | |
} | |
} | |
static void fixed_point(int32_t *buf, int count) | |
{ | |
int32_t left, right; | |
get_smpl(left, right); | |
static constexpr int FPSHIFT = 10; | |
int tickval = (1 << FPSHIFT) / count; | |
if(tickval < 1) | |
tickval = 1; | |
int tickmul = tickval * count; | |
#define DO_MULT(x) (tickmul * ((x) >> FPSHIFT)) | |
while((tickmul -= tickval)) | |
{ | |
*buf++ += DO_MULT(DO_MULT(left)); | |
*buf++ += DO_MULT(DO_MULT(right)); | |
} | |
} | |
static void fixed_point64(int32_t *buf, int count) | |
{ | |
int32_t left, right; | |
get_smpl(left, right); | |
static constexpr uint64_t FPSHIFT = 20; | |
int32_t tickval = (1 << FPSHIFT) / count; | |
if(tickval < 1) | |
tickval = 1; | |
int32_t tickmul = tickval * count; | |
while((tickmul -= tickval)) | |
{ | |
*buf++ += (tickmul * (int64_t)tickmul * (int64_t)(left >> 8)) >> (FPSHIFT * 2 - 8); | |
*buf++ += (tickmul * (int64_t)tickmul * (int64_t)(right >> 8)) >> (FPSHIFT * 2 - 8); | |
} | |
} | |
static void fixed_point_hybrid(int32_t *buf, int count) | |
{ | |
int32_t left, right; | |
get_smpl(left, right); | |
static constexpr uint32_t FPSHIFT = 24; | |
int32_t tickval = (1 << FPSHIFT) / count; | |
if(tickval < 1) | |
tickval = 1; | |
int32_t tickmul = tickval * count; | |
uint32_t tickmul_sq; | |
while((tickmul -= tickval)) | |
{ | |
/* Truncate to 16-bits of precision so the product is 32-bits. */ | |
tickmul_sq = tickmul >> (FPSHIFT - 16); | |
tickmul_sq *= tickmul_sq; | |
*buf++ += (tickmul_sq * (int64_t)left) >> 32; | |
*buf++ += (tickmul_sq * (int64_t)right) >> 32; | |
} | |
} | |
template<void (*TESTFN)(int32_t *buf, int count)> | |
__attribute__((noinline)) | |
static void do_test(const char *name, std::vector<int32_t> &buf, const std::vector<int32_t> &compare) | |
{ | |
auto start_time = std::chrono::steady_clock::now(); | |
for(size_t i = 0; i < EXEC_TIMES; i++) | |
TESTFN(buf.data(), buf.size() / 2); | |
auto end_time = std::chrono::steady_clock::now(); | |
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time); | |
printf("%-25s: %.3f ms\n", name, (double)duration.count() / 1000.0); | |
// Verify output. | |
std::vector<int32_t> verify(compare.size()); | |
TESTFN(verify.data(), verify.size() / 2); | |
FILE *fp = fopen(name, "wb"); | |
fputs("[ ", fp); | |
// static constexpr int32_t THRESHOLD = (1 << 8); | |
// size_t errcount = 0; | |
for(size_t i = 0; i < buf.size(); i += 2) | |
{ | |
if(i == 0) | |
fprintf(fp, "[ %6d, %6d ]", verify[i], verify[i+1]); | |
else | |
fprintf(fp, ",\n [ %6d, %6d ]", verify[i], verify[i+1]); | |
/* | |
// Allow slight error... | |
int32_t diff = verify[i] - compare[i]; | |
if(diff >= THRESHOLD || diff <= -THRESHOLD) | |
errcount++; | |
diff = verify[i+1] - compare[i+1]; | |
if(diff >= THRESHOLD || diff <= -THRESHOLD) | |
errcount++; | |
*/ | |
} | |
// if(errcount) | |
// printf(" found %zu samples with error of >=%d\n", errcount, THRESHOLD); | |
fflush(stdout); | |
fputs(" ];", fp); | |
fclose(fp); | |
} | |
int main() | |
{ | |
std::vector<int32_t> old_output(BUFFERSIZE * 2); | |
std::vector<int32_t> buf(BUFFERSIZE * 2); | |
old_algorithm(old_output.data(), old_output.size() / 2); | |
do_test<old_algorithm>("Old algorithm", buf, old_output); | |
do_test<floating_point>("Single precision floats", buf, old_output); | |
do_test<double_floating_point>("Double precision floats", buf, old_output); | |
do_test<fixed_point>("Fixed point", buf, old_output); | |
do_test<fixed_point64>("Fixed point 64-bit", buf, old_output); | |
do_test<fixed_point_hybrid>("Fixed point hybrid", buf, old_output); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment