From ad63d5640b7748de872cdf17b7cd642407aca28b Mon Sep 17 00:00:00 2001 From: HP <2726519488@qq.com> Date: Fri, 10 Jul 2026 14:22:29 +0800 Subject: [PATCH] 111 --- src/Apps/Game/CMakeLists.txt | 4 +- src/Apps/Game/Main.cpp | 4 +- src/Apps/Game/README.md | 446 ++-- .../src/recognition/ResBnKwsModelData.cpp | 1804 +++++++++++++++++ .../Game/src/recognition/ResBnKwsModelData.h | 106 + .../src/recognition/ResBnKwsRecognizer.cpp | 1130 +++++++++++ .../Game/src/recognition/ResBnKwsRecognizer.h | 50 + 7 files changed, 3384 insertions(+), 160 deletions(-) create mode 100644 src/Apps/Game/src/recognition/ResBnKwsModelData.cpp create mode 100644 src/Apps/Game/src/recognition/ResBnKwsModelData.h create mode 100644 src/Apps/Game/src/recognition/ResBnKwsRecognizer.cpp create mode 100644 src/Apps/Game/src/recognition/ResBnKwsRecognizer.h diff --git a/src/Apps/Game/CMakeLists.txt b/src/Apps/Game/CMakeLists.txt index bb134ae..5101059 100644 --- a/src/Apps/Game/CMakeLists.txt +++ b/src/Apps/Game/CMakeLists.txt @@ -14,8 +14,8 @@ add_executable(${TOM_GAME_TARGET} src/gameplay/TomHud.cpp src/gameplay/VoiceInteractionController.cpp src/recognition/KeywordRecognizer.cpp - src/recognition/TinyKwsRecognizer.cpp - src/recognition/TinyKwsModelData.cpp + src/recognition/ResBnKwsRecognizer.cpp + src/recognition/ResBnKwsModelData.cpp src/ui/TomSettingsPanel.cpp ${TOM_ATLAS_HEADER} ) diff --git a/src/Apps/Game/Main.cpp b/src/Apps/Game/Main.cpp index de26280..52a43c9 100644 --- a/src/Apps/Game/Main.cpp +++ b/src/Apps/Game/Main.cpp @@ -13,7 +13,7 @@ #include "Timer.h" #include "app/TomGameApp.h" #include "recognition/KeywordRecognizer.h" -#include "recognition/TinyKwsRecognizer.h" +#include "recognition/ResBnKwsRecognizer.h" #ifdef TARGET_IMX #include "FBDisplay.h" @@ -349,7 +349,7 @@ int main(int argc, char *argv[]) Platform::DefaultButtonInput buttonInput; Platform::DefaultPointerInput pointerInput; - Game::TinyKwsRecognizer keywordRecognizer; + Game::ResBnKwsRecognizer keywordRecognizer; keywordRecognizer.set_confidence_threshold(options.kws_threshold); keywordRecognizer.set_input_gain(options.kws_input_gain); diff --git a/src/Apps/Game/README.md b/src/Apps/Game/README.md index d091801..64706ae 100644 --- a/src/Apps/Game/README.md +++ b/src/Apps/Game/README.md @@ -1,239 +1,373 @@ -# Tom Game 语音识别与板端运行 +# TomGame、Desktop 与板端部署 -本文说明 Tom Game 当前的关键词识别链路、Windows 验证方式,以及 IMX6ULL-ALPHA 板端构建/部署流程。 +本文说明 TomGame 当前的关键词识别方式,以及 Windows 验证、WSL +交叉编译、Windows SCP 部署和 IMX6ULL 板端运行流程。 -## 当前结论 +TomGame 使用内嵌的 `ResBnKwsRecognizer` INT8 模型,不需要 Python、 +TensorFlow、TensorFlow Lite 运行库或外部模型文件。 -- 游戏内识别器是 `src/recognition/TinyKwsRecognizer.cpp`。 -- 模型权重已从 `kws_ref_model_float32.tflite` 导出并内嵌到 `src/recognition/TinyKwsModelData.cpp`。 -- Windows 和 IMX6ULL 板端现在都默认走同一套 C++ 内嵌推理,不再调用 Python 子进程,也不再链接 TensorFlow Lite C API。 -- 构建和部署不再需要 `libtensorflowlite_c.so`、TensorFlow Lite 头文件、`TOM_GAME_ENABLE_TFLITE_C_API`、`TOM_GAME_TFLITE_INCLUDE_DIR` 或 `TOM_GAME_TFLITE_LIBRARY`。 -- `--kws-model` 参数已废弃。模型权重已经编译进可执行文件,运行时不会加载外部 `.tflite` 文件。 -- 仍可使用 `--kws-threshold` 调整识别置信度阈值,默认是 `0.75`。 -- 仍可使用 `--kws-input-gain` 调整 KWS 归一化后的输入增益,默认是 `1.0`。 -- 12 个模型类别是 `Down, Go, Left, No, Off, On, Right, Stop, Up, Yes, Silence, Unknown`。 -- 当前游戏动作映射是 `Up/On -> Jump`,`Stop -> Idle`,其他类别暂不触发动作。 - -## 识别链路 - -当前板端完整链路如下: +模型支持以下 12 个类别: ```text -AudioInput PCM --> VoiceRecorder --> VoiceInteractionController --> TinyKwsRecognizer --> 16 kHz / mono / trim silence --> MFCC feature extraction --> embedded DS-CNN forward pass --> KeywordCommand --> KeywordCommandRouter --> TomGameState +Down, Go, Left, No, Off, On, Right, Stop, Up, Yes, Silence, Unknown ``` -内嵌模型只实现当前 Tiny KWS 模型需要的固定算子: +当前游戏动作映射: ```text -Conv2D -DepthwiseConv2D -AveragePool2D -Reshape -FullyConnected -Softmax +Up / On -> Jump +Stop -> Idle ``` -该实现不是通用 TFLite runtime,只服务于当前 `kws_ref_model_float32.tflite` 导出的固定网络结构。 - ## Windows 验证 -Windows 游戏现在也默认使用 C++ 内嵌模型。构建并运行游戏后,点击左侧 `ui-hand` 按钮切到语音识别模式,再按录音按钮测试。 +Windows 版本和板端版本使用同一套 C++ 特征提取、INT8 模型推理和 +多窗口融合逻辑,不再需要 Python 对照脚本。 -常用运行方式: +在项目根目录构建 TomGame: ```powershell -IMX6U-Game.exe --fps 30 --kws-threshold 0.75 --kws-input-gain 1.0 +cmake --build build --config Release --target IMX6U-Game ``` -旧参数 `--kws-model` 会被忽略: +直接运行: + +```powershell +.\build\Release\IMX6U-Game.exe ` + --fps 30 ` + --kws-threshold 0.75 ` + --kws-input-gain 1.0 +``` + +程序支持以下关键词识别参数: ```text ---kws-model is ignored: Tiny KWS weights are embedded in the executable. +--kws-threshold 识别置信度阈值,默认 0.75 +--kws-input-gain MFCC 输入增益,范围 (0, 1],默认 1.0 ``` -Python 脚本仍可作为离线对照工具,用于比较 `.tflite` 原模型输出和 C++ 内嵌推理输出: - -```powershell -python src\Apps\Game\tools\kws_python_test.py --wav src\Apps\Game\model\mlcommons-tiny-kws\down_0c40e715_nohash_0.wav -python src\Apps\Game\tools\kws_python_test.py --wav src\Apps\Game\model\mlcommons-tiny-kws\no_0cb74144_nohash_1.wav -``` - -如果需要验证 Python 环境: - -```powershell -python -c "import tensorflow as tf; import numpy as np; print(tf.__version__); print(np.__version__)" -``` - -已知对齐情况: +识别成功或未达到阈值时,控制台会打印类似日志: ```text -down_0c40e715_nohash_0.wav: - Python TFLite: Down @ ~0.9388 - C++ embedded: Down @ ~0.9366 - -no_0cb74144_nohash_1.wav: - Python TFLite: Go @ ~0.7522 - C++ embedded: Go @ ~0.7080, below default threshold +[INFO] ResBN INT8 KWS result: command=Up, confidence=0.92, windows=... ``` -`no` 样例处在阈值边缘,C++ 自研 FFT/MFCC 与 Python/TFLite 的浮点细节差异会影响置信度。如果要让边界样例更容易通过,可临时降低阈值,例如: +Windows Desktop 和全部游戏可以一起构建: ```powershell -IMX6U-Game.exe --kws-threshold 0.70 +cmake --build build --config Release --target ` + IMX6U-Desktop ` + IMX6U-Game ` + IMX6U-LightGame ` + IMX6U-Demo ``` -如果日志长期显示 `class=Unknown`,可以先尝试提高输入增益: +运行主页: ```powershell -IMX6U-Game.exe --fps 30 --kws-threshold 0.70 --kws-input-gain 1.5 +.\build\Release\IMX6U-Desktop.exe ``` -## IMX6ULL-ALPHA 板端构建 +Desktop 会从自身所在目录寻找并启动以下程序: -在 WSL2 项目根目录下构建 framebuffer 板端版本: - -```bash -cd ~/IMX6U-Game - -rm -rf build-arm-fb - -cmake -B build-arm-fb \ - -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-linux-gnueabihf.cmake \ - -DTARGET_IMX=ON \ - . - -cmake --build build-arm-fb --target IMX6U-Game -j$(nproc) +```text +IMX6U-Game.exe +IMX6U-LightGame.exe +IMX6U-Demo.exe ``` -`TARGET_IMX=ON` 必须能找到 ALSA 头文件和 ARMHF 版 `libasound`。在 WSL 中推荐直接安装 ARMHF 开发包: +因此 Desktop 和各游戏的可执行文件需要位于同一个目录。 + +## WSL 交叉编译 + +### 1. 安装工具链 + +首次编译时安装 ARM 交叉编译器和 ALSA 开发文件: ```bash sudo dpkg --add-architecture armhf sudo apt update -sudo apt install -y libasound2-dev:armhf +sudo apt install -y \ + cmake \ + build-essential \ + gcc-arm-linux-gnueabihf \ + g++-arm-linux-gnueabihf \ + libasound2-dev:armhf ``` -由于 ATK-IMX6U 的系统较老,不要链接 WSL 自带的新版 ARMHF `libasound.so`。从板子复制匹配的 ALSA 运行库到项目内: +检查交叉编译器: + +```bash +arm-linux-gnueabihf-g++ --version +``` + +### 2. 确认生成资源 + +交叉编译不会在板端生成 PNG 图集。开始编译前确认以下文件存在: + +```bash +ls src/Apps/Game/generated/tom_atlas.h +ls src/Apps/Desktop/generated/desktop_atlas.h +``` + +如果文件不存在,先在 Windows 主机构建一次对应目标,生成图集后再同步到 +WSL 源码目录。 + +### 3. 配置并编译 + +在 WSL 项目根目录执行: + +```bash +rm -rf build-arm-fb + +cmake -S . -B build-arm-fb \ + -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-linux-gnueabihf.cmake \ + -DTARGET_IMX=ON \ + -DCMAKE_BUILD_TYPE=Release + +cmake --build build-arm-fb \ + --target \ + IMX6U-Desktop \ + IMX6U-Game \ + IMX6U-LightGame \ + IMX6U-Demo \ + -j"$(nproc)" +``` + +查找编译产物: + +```bash +find build-arm-fb -type f \ + \( -name IMX6U-Desktop \ + -o -name IMX6U-Game \ + -o -name IMX6U-LightGame \ + -o -name IMX6U-Demo \) +``` + +使用 `file` 确认产物是 ARM 程序: + +```bash +file "$(find build-arm-fb -type f -name IMX6U-Desktop | head -n 1)" +file "$(find build-arm-fb -type f -name IMX6U-Game | head -n 1)" +file "$(find build-arm-fb -type f -name IMX6U-LightGame | head -n 1)" +file "$(find build-arm-fb -type f -name IMX6U-Demo | head -n 1)" +``` + +正确结果应包含: ```text -third_party/arm-linux-gnueabihf/alsa/lib/libasound.so -third_party/arm-linux-gnueabihf/alsa/lib/libasound.so.2 -third_party/arm-linux-gnueabihf/alsa/lib/libasound.so.2.0.0 +ELF 32-bit LSB executable, ARM, EABI5 ``` -CMake 会优先使用这个项目内库目录;ALSA 头文件可继续来自 WSL 的 `libasound2-dev:armhf`。 +如果显示 `x86-64`,说明没有使用 ARM 工具链。 -不需要再传这些旧参数: +## Windows SCP 部署 -```bash --DTOM_GAME_ENABLE_TFLITE_C_API=ON --DTOM_GAME_TFLITE_INCLUDE_DIR=... --DTOM_GAME_TFLITE_LIBRARY=... -``` - -构建产物位置可用以下命令确认: - -```bash -find build-arm-fb -name IMX6U-Game -type f -``` - -## 板端部署与运行 - -假设板子地址是 `root@imx6u`: - -```bash -ssh root@imx6u 'mkdir -p /opt/imx6u-game' -scp "$(find build-arm-fb -name IMX6U-Game -type f | head -n 1)" root@imx6u:/opt/imx6u-game/ -``` - -不需要再拷贝: +将 WSL 编译出的四个程序复制到 Windows。以下示例假设文件位于: ```text -libtensorflowlite_c.so -kws_ref_model_float32.tflite +E:\嵌入式实验\IMX6U-Desktop +E:\嵌入式实验\IMX6U-Game +E:\嵌入式实验\IMX6U-LightGame +E:\嵌入式实验\IMX6U-Demo ``` -运行前先检查麦克风: +板子地址示例: -```bash -arecord -l -aplay -l -arecord -L -aplay -L - -arecord -D sysdefault:CARD=wm8960audio -f S16_LE -r 16000 -c 1 -d 2 /tmp/kws_mic_test.wav -aplay -D sysdefault:CARD=wm8960audio /tmp/kws_mic_test.wav +```text +root@192.168.0.200 ``` -ATK-IMX6U 板载 WM8960 通常显示为 `wm8960audio`。如果 `sysdefault:CARD=wm8960audio` 不可用,可尝试硬件设备: +板端统一部署目录: -```bash -arecord -D plughw:0,0 -f S16_LE -r 16000 -c 1 -d 2 /tmp/kws_mic_test.wav -aplay -D plughw:0,0 /tmp/kws_mic_test.wav +```text +/home/root/opt ``` -程序默认仍使用 ALSA `"default"`,也可以通过启动参数显式指定输入/输出设备,避免依赖 `/etc/asound.conf` 或 `~/.asoundrc`。 +先创建目录: -启动游戏: +```powershell +ssh ` + -o HostKeyAlgorithms=+ssh-rsa ` + root@192.168.0.200 ` + "mkdir -p /home/root/opt" +``` + +批量上传: + +```powershell +$files = @( + "IMX6U-Desktop", + "IMX6U-Game", + "IMX6U-LightGame", + "IMX6U-Demo" +) + +foreach ($file in $files) { + scp -O ` + -o HostKeyAlgorithms=+ssh-rsa ` + "E:\嵌入式实验\$file" ` + "root@192.168.0.200:/home/root/opt/$file" +} +``` + +其中: + +```text +-O 强制使用旧版 SCP 协议 +HostKeyAlgorithms=+ssh-rsa 兼容板子上的旧 SSH 服务 +``` + +ResBN 模型已经编译进 `IMX6U-Game`,不需要上传 `.tflite` 或其他模型文件。 + +## 板端运行 + +### 1. 登录板子 + +```powershell +ssh -o HostKeyAlgorithms=+ssh-rsa root@192.168.0.200 +``` + +### 2. 初始化音频 ```bash -cd /opt/imx6u-game cd /home/root/shell/audio ./mic_in_config.sh amixer cset numid=41 1 +``` + +`amixer cset numid=41 1` 会将 WM8960 的左 ADC 同时输出到左右声道。 +板载 MIC 实测主要连接在 Left ADC,未设置时可能只有单声道有效。 + +### 3. 设置执行权限 + +```bash +cd /home/root/opt +chmod +x IMX6U-Desktop +chmod +x IMX6U-Game +chmod +x IMX6U-LightGame +chmod +x IMX6U-Demo +``` + +也可以统一执行: + +```bash +chmod +x IMX6U-* +``` + +### 4. 启动 Desktop + +```bash +cd /home/root/opt +./IMX6U-Desktop +``` + +Desktop 操作方式: + +```text +点击屏幕左侧或右侧 切换游戏 +水平滑动 切换游戏 +点击中间游戏封面 启动当前游戏 +``` + +Desktop 启动游戏前会释放 framebuffer 和触摸设备。游戏退出后, +Desktop 会重新初始化硬件并恢复主页。 + +Desktop 使用相对路径启动游戏,因此以下程序必须与 `IMX6U-Desktop` +处于同一目录: + +```text +/home/root/opt/IMX6U-Desktop +/home/root/opt/IMX6U-Game +/home/root/opt/IMX6U-LightGame +/home/root/opt/IMX6U-Demo +``` + +### 5. 单独运行 TomGame + +排查语音或音频问题时,可以绕过 Desktop 直接启动 TomGame: + +```bash +cd /home/root/opt -cd /opt/imx6u-game ./IMX6U-Game \ --fps 30 \ - --kws-threshold 0.70 \ - --kws-input-gain 1.5 \ + --kws-threshold 0.75 \ + --kws-input-gain 1.0 \ --audio-input-device sysdefault:CARD=wm8960audio \ --audio-output-device sysdefault:CARD=wm8960audio ``` -其中 `amixer cset numid=41 1` 将 WM8960 的左 ADC 同时输出到左右声道。IMX6ULL-ALPHA 板载 MIC 实测主要接在 Left ADC,如果不设置该项,录音可能只有左声道有效,播放或游戏回放时可能只听到噪声。 - -如果 `sysdefault:CARD=wm8960audio` 初始化失败,再换成: +如果 `sysdefault:CARD=wm8960audio` 初始化失败,改用: ```bash -cd /home/root/shell/audio -./mic_in_config.sh -amixer cset numid=41 1 - -cd /opt/imx6u-game ./IMX6U-Game \ --fps 30 \ - --kws-threshold 0.70 \ - --kws-input-gain 1.5 \ + --kws-threshold 0.75 \ + --kws-input-gain 1.0 \ --audio-input-device plughw:0,0 \ --audio-output-device plughw:0,0 ``` -进入游戏后: +Desktop 启动 TomGame 时不会附加命令行参数,因此 TomGame 会使用 ALSA +的 `"default"` 输入和输出设备。如果直接运行 TomGame 正常,但从 Desktop +启动后音频初始化失败,需要将板子的 ALSA default 配置映射到 WM8960。 -1. 点击左侧 `ui-hand` 切到语音识别模式。 -2. 点击录音按钮。 -3. 说 `Up` / `On` / `Stop`。 -4. 观察 Tom 是否跳跃或回到 Idle。 +## 常见问题 -## 排查顺序 +### SSH 提示不支持 ssh-rsa -1. `IMX6U-Game` 能启动并正常刷新画面。 -2. 程序启动后不再打印 `AlsaAudioInput backend is unavailable`;如果仍打印,说明当前二进制没有编进 ALSA,需要重新交叉编译并部署。 -3. 运行 `/home/root/shell/audio/mic_in_config.sh`,再执行 `amixer cset numid=41 1`,确保板载 MIC 的 Left ADC 映射到左右声道。 -4. `arecord -D sysdefault:CARD=wm8960audio` 或 `arecord -D plughw:0,0` 能录到 16-bit 音频,且说话时 `arecord -vv` 音量条有明显波动。 -5. `aplay -D sysdefault:CARD=wm8960audio` 或 `aplay -D plughw:0,0` 能从扬声器放出录音。 -6. 游戏中已切到左侧 `ui-hand` 语音识别模式。 -7. 试用较低阈值确认链路,例如 `--kws-threshold 0.70`。 -8. 如果模型日志长期显示 `class=Unknown`,尝试提高输入增益,例如 `--kws-input-gain 1.5`。 -9. 如果仍然没有识别结果,优先检查 WM8960 混音器开关、麦克风增益、采样率、ALSA 设备名和录音幅度。 -10. 如果边界词不稳定,再对齐 C++ MFCC 与 Python/TFLite 前处理细节。 +错误示例: + +```text +Unable to negotiate ... no matching host key type found. +Their offer: ssh-rsa +``` + +连接时增加: + +```text +-o HostKeyAlgorithms=+ssh-rsa +``` + +SCP 还建议增加 `-O`,以兼容板子上的旧版 SSH/Dropbear。 + +### 找不到 libasound + +项目会优先使用: + +```text +third_party/arm-linux-gnueabihf/alsa/lib/libasound.so +``` + +如果该文件不存在,需要安装兼容的 ARMHF ALSA 包,或者从板子复制匹配的 +`libasound.so*` 到该目录。不要使用与板端系统版本不兼容的新版库。 + +### Desktop 可以启动,但点击游戏没有反应 + +检查四个程序是否位于同一个目录,并具有执行权限: + +```bash +cd /home/root/opt +ls -l IMX6U-* +``` + +Desktop 的游戏目录配置为: + +```text +TomGame -> IMX6U-Game +LightGame -> IMX6U-LightGame +Demo -> IMX6U-Demo +``` + +### TomGame 没有识别结果 + +按以下顺序检查: + +1. 执行 `mic_in_config.sh` 和 `amixer cset numid=41 1`。 +2. 使用 `arecord -l`、`arecord -L` 确认 WM8960 设备存在。 +3. 使用 `arecord -vv` 检查说话时是否有明显音量变化。 +4. 确认游戏已切换到关键词识别模式。 +5. 检查日志中是否出现 `ResBN INT8 KWS result`。 +6. 保持 `--kws-input-gain` 在 `(0, 1]` 范围。 +7. 必要时将 `--kws-threshold` 从 `0.75` 临时降低到 `0.70` 进行链路测试。 diff --git a/src/Apps/Game/src/recognition/ResBnKwsModelData.cpp b/src/Apps/Game/src/recognition/ResBnKwsModelData.cpp new file mode 100644 index 0000000..3ca5ad1 --- /dev/null +++ b/src/Apps/Game/src/recognition/ResBnKwsModelData.cpp @@ -0,0 +1,1804 @@ +#include "ResBnKwsModelData.h" + +namespace Game +{ +namespace ResBnKwsModelData +{ +const int8_t StemWeights[2560] = +{ + 23, 7, 3, -23, 14, -22, -9, 21, 24, -21, -9, -25, 6, -23, -5, 6, + -15, -5, -1, -18, -28, -18, 5, -17, -4, -127, 26, -18, -12, -86, 26, 43, + -11, -19, -18, 4, 20, 97, 17, 15, 53, 127, 66, 51, 30, 122, 69, -41, + 71, 60, 54, -55, 67, 42, 17, -62, 43, -30, -56, -39, -40, 7, -86, -31, + -37, -39, -69, -65, 19, -49, -28, -61, -13, -41, -63, 50, 15, 1, -79, 38, + 12, 6, 86, 41, 18, -61, 35, 66, -4, -22, -6, -58, 62, 43, -56, -127, + 74, 32, -23, -13, 24, 15, -34, 14, -47, 27, -5, -13, -16, 22, 18, 7, + -11, -7, -10, -5, -24, 8, -30, 19, -23, -28, -87, 22, -11, -6, -83, -6, + 0, -3, -18, -6, 40, 70, -25, -12, 107, 103, -26, -1, 85, 46, 13, -1, + 66, 76, 127, 66, 37, 7, 48, 18, -67, -34, 69, 16, -63, 0, 58, -43, + -53, 74, -8, -88, -19, 20, 78, -68, 43, 84, 101, -22, 62, 6, 89, -27, + 81, 42, 65, 16, 7, -3, 10, 16, -26, -76, 45, 81, -37, -41, -36, 57, + -12, -24, -109, 25, 11, -11, -127, -1, 58, 13, -85, 63, 25, -20, -87, 28, + -44, -22, -51, 67, -48, -16, -59, -7, -56, 15, 44, -5, -48, 40, 80, 17, + -29, 77, 100, -42, 7, 39, 127, -2, 42, 62, 105, -4, 39, -3, 65, -8, + 61, 5, -52, 46, 39, -24, -11, -35, 35, -49, -8, -89, -13, -51, -73, -67, + -84, 95, -37, -15, -40, 72, 72, -83, 80, 58, 30, -64, 127, -2, 0, -29, + 41, -3, 89, 25, -58, -9, 12, 49, 18, 78, -34, 5, -3, 127, -10, -41, + -33, 50, -10, -18, -60, 36, 10, 30, -37, 58, 51, -19, -24, -11, 45, -20, + -25, -65, 13, -21, -7, -24, 45, 13, 12, -28, -18, -50, 44, -39, 22, -62, + -1, 84, -42, -127, -21, 33, -57, -80, -60, -11, -43, 12, -92, -5, 5, 54, + -45, 16, 27, 94, 1, 6, 65, 73, 15, 17, 49, 11, 33, -26, 87, 21, + 53, 18, 32, -52, 120, -21, 0, -96, -11, -15, -6, -61, 4, 2, -30, -117, + -61, -41, -36, -124, -27, -64, -44, -20, -25, -43, 18, 55, -10, 6, 64, 127, + 7, 2, 30, 88, 13, 7, 31, 75, 33, 40, 14, 45, 2, 48, 22, 44, + -19, 49, 64, 84, 39, 112, 26, -21, -39, 46, -23, 44, -93, -8, -124, 59, + 14, 16, -79, -123, 66, -7, -38, -57, 75, 43, 6, -127, 124, -9, -41, -101, + 78, -7, 6, -56, -18, -2, -17, -19, 1, -7, 45, -15, 23, -20, -1, 35, + 23, -16, -2, 74, -14, 33, 16, 127, -22, 42, 14, 88, 16, 32, -30, -14, + 4, -1, -50, -73, 0, -13, -26, -56, -2, -14, 12, -30, -8, 12, 3, -17, + 63, 92, 0, -113, 113, 56, -43, 24, 42, 115, -127, 34, 19, 66, -70, 124, + -11, 12, -46, 83, -21, -77, 35, 124, -119, -85, 56, 30, -2, -51, 70, 36, + 29, 21, 93, -59, -10, 7, 107, -15, 92, -55, -127, -69, 92, -57, -106, -88, + 7, -32, -37, -24, 13, -15, -31, 10, 11, -47, -22, 57, 35, -15, 47, 100, + -40, -9, -40, 20, -33, 19, -19, 13, -14, -2, 1, -27, 0, -13, -22, -73, + -27, 4, 109, -43, -80, -10, 127, -62, -63, 15, 39, -15, -61, 9, 15, 2, + 2, 9, -1, 34, 6, 9, 20, -22, -16, 5, 15, -28, 20, -2, 28, -9, + 13, -15, 23, -29, -7, -18, 14, -28, 21, -38, 14, 33, 29, -12, -40, 30, + -4, -56, -31, 64, 16, -29, -61, 48, -12, 17, -127, 36, 41, -7, -101, -14, + 7, 15, -39, 5, 70, -2, -47, -11, 48, 43, 50, 43, -20, 4, 35, 37, + -80, 8, -43, 50, -14, 27, -114, 20, -11, 19, -99, 72, -29, 39, -55, 22, + -24, -13, -30, -52, -10, -1, 38, -23, -61, -61, 48, -52, -15, -36, 48, -127, + -4, -55, 48, -99, -32, -24, 58, -94, -54, 47, 12, 6, -1, -22, -4, 10, + -26, 45, -13, 8, -14, -33, -51, -3, -19, 6, -47, -23, -22, -12, 11, 117, + 41, -127, 76, 93, -4, -81, 16, 0, -8, 51, -15, -67, 13, 74, 5, -67, + 61, -52, -8, -4, 8, 12, -55, 60, 58, 50, -57, 102, -30, 73, -25, -4, + 11, 35, -37, 71, -94, -33, 48, 75, -3, -127, 18, 30, -32, -63, 11, 45, + -50, -26, 43, 66, 7, -10, 20, 57, -76, -7, 127, -114, -34, 70, 87, -67, + -40, 74, -10, -35, -14, 29, -5, -8, 32, -10, 35, 19, 47, -10, 7, 14, + 30, 13, 8, 2, 24, 32, 51, 2, 16, 57, 54, 34, 26, -9, 5, 28, + -7, -115, 98, 18, -26, -90, 89, -53, -25, -25, 13, -78, -49, 68, -4, -88, + -4, 127, -39, -50, -33, 47, -102, 1, -15, 30, -88, 76, 45, -6, 7, 56, + 8, -39, 80, 66, -59, 4, 8, 83, 5, -28, -84, -22, -16, -58, 2, -15, + 18, -29, 64, 5, 38, -19, 35, 30, 29, -32, 92, 48, 1, 4, 40, 75, + 13, 34, -10, 43, -19, 51, 83, 13, -7, 127, 91, 8, -52, 71, 36, -14, + -7, 24, 48, -71, -2, 33, -31, -43, 80, 12, -60, -115, 49, -16, -91, -15, + -29, -44, -38, 56, -43, -77, -68, 127, 34, -50, -11, 105, 37, -4, 66, 120, + 116, -14, 30, 5, 82, 3, 93, -12, -40, 65, 84, -20, -49, 26, 7, 28, + -28, 66, -44, -69, -127, 86, 53, 96, -72, 58, 108, 39, 125, 47, 46, 41, + 5, -104, -19, -48, -21, -75, -17, -68, -22, -25, -118, -117, 34, -22, -91, -75, + -1, -20, -44, -23, -23, -41, 60, 52, -83, 20, 91, 97, -109, 38, 112, 27, + -85, 65, 31, 4, -5, -27, 52, -35, 23, 33, -66, -93, 48, 16, 23, -93, + 46, 71, -62, -105, 98, 111, -72, -127, -15, 63, -22, 8, -17, 71, -50, -40, + -1, 72, -75, -82, 5, 52, -59, -127, 32, 5, -64, -99, 48, -64, -38, -28, + 32, -55, -46, -15, -19, -76, 67, -10, -55, 18, 97, 43, 0, 30, 82, 64, + -55, 18, 38, -18, -21, 9, 56, -96, 14, 24, 68, -53, 19, 3, 53, -13, + -17, -43, -26, 52, -8, -78, -127, 71, 14, -37, -81, 98, 7, -17, -41, 39, + 29, 23, 5, 3, 45, 48, 39, 8, 70, 72, -66, 54, 31, 77, 50, 24, + -21, 38, -24, 57, -4, -69, 90, 53, -50, -52, 8, 71, 30, 1, 30, -13, + -5, -127, 35, -11, -24, -78, -1, 28, 26, -5, -65, -31, -27, 30, -101, -18, + 46, -32, 56, -19, 34, -23, -17, -64, -22, -23, -113, 13, -109, 40, 12, 122, + -106, 65, 127, 102, -52, 107, 102, 24, 1, 56, 60, -39, 41, -27, -44, -70, + -3, 12, -100, 14, 20, 3, -40, -29, -13, -79, 14, -5, 43, -21, -72, -43, + 19, 31, -41, 49, -20, 45, -102, 57, -44, -33, -26, 51, -34, -54, 44, -10, + -48, -12, 107, -16, -56, 0, 91, -4, 24, 127, 30, -70, 29, 116, -27, -46, + -26, -7, -49, 48, 16, 52, 21, 84, -30, 68, 50, 76, -127, 24, 74, 36, + -78, -15, 94, 20, -54, -7, -6, -52, 20, 17, -23, -85, 29, 67, -41, -106, + 98, 8, -20, -105, 89, -30, -6, -20, 31, -35, 31, -37, -22, -20, 34, 11, + -86, -6, 26, 37, -29, 78, -3, 12, 2, 101, -44, 22, 10, 39, -9, 19, + 49, -35, -19, -61, -13, -13, 9, -127, 9, 49, 7, -63, 9, 79, 0, -57, + -38, 111, 51, 13, -1, 84, -36, -5, 29, 45, -102, -61, 127, 7, 3, -22, + 61, -33, 54, -51, -27, -59, 91, 9, -97, -55, 63, -56, -98, 15, -4, -17, + -47, 9, -15, 12, -9, -29, 22, 7, 0, -22, 63, 70, -17, 23, -99, 66, + -10, -21, -106, 11, -9, -23, -99, -59, 13, -108, -127, -36, -8, -46, -94, -59, + 42, -31, -50, -4, 57, -21, 104, 60, -11, -62, 15, 28, 10, -20, -18, 84, + 15, 24, 43, -45, -4, 30, 51, -17, -30, -32, 103, 11, -66, -59, 120, 27, + -62, -127, 29, 50, -21, -38, -35, 56, 16, -35, -90, -17, 40, -12, -77, 20, + 47, 63, -72, 6, 54, 67, -57, -28, -53, 7, -57, 60, -46, -31, -112, 75, + 19, -27, -28, 70, -5, -17, 4, 39, 37, -6, -20, 19, 52, -26, -22, 15, + 35, -1, 8, 65, 84, -5, 47, 0, 127, -17, 53, 18, 69, 14, 106, -29, + 62, 12, 80, 21, 83, -9, 30, 35, 42, -5, -26, 96, -46, 21, -83, 127, + -71, 48, -77, 38, -70, 17, -26, -44, -38, -48, 68, -105, -23, -25, 44, -50, + 43, -6, 10, -61, 45, -6, 2, -59, -31, 16, 10, -127, -55, 62, 26, -89, + -56, 98, 80, -98, -31, 59, 14, -18, 9, 58, -20, 0, 63, -56, -56, 33, + 55, -47, -80, 67, 10, -36, -21, 41, 18, -1, -44, 66, 23, 21, -16, 55, + 2, -4, 91, -75, -35, 2, 35, -95, -89, 49, -5, -94, -127, 58, 59, -5, + -38, -14, -11, 69, 96, -57, -14, 111, 107, 5, -94, 31, 73, -5, -39, 30, + 46, -2, -43, 12, -8, -2, 46, -23, -39, -74, -67, 66, -53, -127, -6, 79, + -39, -86, -13, 77, 9, -45, -21, 48, 14, 65, -31, 60, 21, -2, 10, 22, + 29, 23, 63, 2, 73, 26, 61, 16, 38, 21, 104, -92, 30, 54, 91, -81, + -57, -80, -73, -35, 94, -4, -76, -58, 49, 101, 0, -127, 19, 118, 101, -119, + -33, 105, 87, -42, -39, 89, -28, -59, 12, -26, 25, -35, 73, -68, 49, 14, + 47, -25, 7, 35, -9, -1, -79, 31, -57, 64, -78, -59, -18, 50, -7, 58, + -33, 23, -22, 54, 18, -52, -18, 127, -10, -33, -66, 49, -28, -41, -27, 49, + -47, -3, -1, -33, 31, -59, 52, 19, -43, -36, 15, -10, -52, -15, 23, -37, + -33, -86, 64, 127, -47, -62, 81, 71, -15, -1, 4, 39, -10, -12, -48, -1, + 29, 20, -53, 0, 19, 31, -31, -55, 14, 40, -45, -52, -9, 28, -5, -120, + -2, 38, -25, -75, 35, 36, 13, -87, -68, -69, 40, -8, 10, -64, -68, -35, + 27, -47, -91, 18, 77, -39, -61, 32, 65, -12, -107, -60, 80, 26, -103, -11, + 79, 60, -49, -70, 43, 43, -23, -49, 28, 50, -18, -68, 48, 42, 12, -127, + 25, 35, -43, -14, 26, -18, -82, 11, 42, 47, -94, -26, 38, -21, -127, 48, + -27, -53, -125, 63, -18, -38, -87, 86, -4, 17, 45, 55, -14, 47, 71, -41, + -14, 20, 98, -18, -23, -11, 98, -29, -79, 31, 64, -35, 101, 79, -5, 14, + 59, 5, 20, -51, -8, 2, 43, -56, -63, -9, 54, -86, -31, 7, 26, -47, + -78, 63, -127, 3, 29, 51, -117, 53, 103, -26, -107, 75, 108, -39, 21, 82, + -44, -36, 19, 41, -16, -20, -2, 32, -29, -4, 61, 55, -18, -20, 16, 104, + 37, -11, -16, 127, -18, -27, -15, 124, -29, -25, -37, 100, -82, 12, -13, 32, + -71, -24, -37, 7, -37, -80, 15, 58, -72, 26, 127, 7, -29, 23, 86, 61, + -34, -30, 21, 107, 3, -3, -73, 50, -1, -28, -93, 29, 50, -28, -93, -50, + 44, -45, -77, -45, 26, 5, -55, -74, 3, -19, -29, -26, 36, -24, 25, 6, + -47, 12, -49, -26, -27, 14, 22, 38, -25, -28, 51, 110, -34, -61, -72, -2, + -13, 11, -127, 31, 5, 83, -35, 33, -7, 113, 80, 29, 30, 23, 90, -37, + 34, -23, 61, -68, 34, -8, 13, -52, -6, 65, 9, 23, -54, -10, 41, 43, + -36, -10, 9, 51, -61, -33, 8, 73, -41, -22, -2, 66, -4, -50, -26, 20, + 30, -28, -6, -64, 63, 13, 43, -90, 21, -2, 69, -127, 60, 57, 14, -26, + 16, -26, 1, -19, 74, -33, 4, -20, -18, 29, -33, 111, -15, -22, -40, 127, + -47, 1, -21, 75, -76, 26, -33, 70, -36, 65, -6, 18, 22, 22, -6, 7, + -40, 4, 17, 14, -42, -5, 23, -12, 22, 11, -70, 95, 101, 17, -104, 52, + 87, -78, -127, 76, -15, -61, -44, -113, -30, -26, 33, -127, -100, 8, -26, -83, + -44, -9, 20, -26, -16, 6, 94, 72, -33, 71, 77, -2, -13, 64, 68, 16, + -93, 72, -120, -127, 34, 80, -22, -118, 31, 28, 44, 24, -30, -40, 101, 31, + -45, -2, 54, 119, -10, 2, -13, 123, 51, 60, -10, 46, -4, 11, 46, -53, + -13, -89, -63, 35, -5, -38, -13, 25, -79, -52, -16, 103, -5, -9, -83, 11, + 32, 8, -94, -83, 46, 21, -8, -111, 19, 99, 25, -74, -26, 51, 38, -127, + -22, 16, 120, -107, -18, 24, 101, -53, -57, 39, 119, 29, -2, -4, 42, 117, + -12, -43, -111, 52, 10, 15, -57, 69, 26, -58, 11, 127, 18, -38, 28, 86, + 56, -3, 2, 77, 3, -44, 60, 46, 38, -46, -10, 48, -33, -57, -1, 14, + -1, -41, 15, 52, -33, -40, 21, 60, 95, 72, -25, 10, 127, 32, -1, 14, + 21, -57, 27, 0, 1, -116, 3, 51, -4, -98, -30, 67, -35, -66, -4, 44, + -57, -63, 35, 38, -39, -20, -13, 2, -70, -16, -6, -13, -36, -3, 51, 8, + 11, -10, 27, -9, 33, 56, -1, 33, -22, 95, 25, 95, -3, 112, 66, 93, + 15, 77, 59, 96, -17, 19, 24, -18, -12, -32, 13, -108, -5, -61, -55, -38, + -4, -58, -72, -127, -4, -36, -54, -105, 8, -5, -38, 43, 30, 7, -18, 25, + -43, 37, -34, 64, -83, -26, 5, 33, 9, 13, 16, -72, 123, 51, 18, -98, + 127, 71, -7, -99, 44, 0, -13, -61, -20, -7, -29, -12, -7, -34, -31, 27, + -31, -62, -47, 2, -96, -63, -45, -88, -127, -69, -80, 35, -121, 20, 29, 37, + -110, 4, 60, 109, -64, 51, 17, 57, 4, 37, -32, 17, 44, 30, -56, -10, + 89, 67, -20, -2, 86, 30, -37, 15, -44, 81, -102, -98, 13, 70, -71, -127, + 73, 17, -62, -14, 23, 62, -117, 4, 18, 68, -32, 40, -37, -51, 3, 8, + -17, -43, 42, 10, 6, -54, 50, 9, -18, -60, 23, 60, -55, -27, -7, 88, + 88, 83, 38, -3, 127, -22, 4, 26, 11, -16, -27, 62, 23, -91, 7, 31, + -49, -71, -53, -86, -16, -7, -37, -49, -31, 32, -71, -27, 11, 8, 14, 86, + 44, -3, 66, 31, -33, -9, 46, 29, 113, 58, 15, -59, 18, 82, -75, 40, + -75, 10, -31, -6, -21, -61, 29, 2, 58, -54, 88, 29, 27, -57, 92, 110, + 28, 44, 25, 127, -105, 97, -24, 7, -121, 82, -77, -120, -85, 94, -34, -32, + 25, -20, 47, 65, -36, -57, 44, 62, -41, -8, 5, 70, -63, -7, 43, 57, + -46, -10, 6, 60, 16, 9, -63, 18, 46, -86, -127, -1, 71, 25, -90, 18, + 26, -28, -83, 18, 36, -30, -20, -34, 47, -45, -94, 67, -46, 21, -69, 81, + -127, 28, -44, 85, -76, -17, 17, 100, -64, -57, -3, 38, -67, 38, -11, 55, + -11, 61, -12, 57, 28, -17, 2, 48, 23, 24, 31, 37, 38, 92, 36, -39 +}; + +const int32_t StemBias[64] = +{ + -1136, 2304, 294, 1932, -231, 1451, 70, 194, + 877, -320, 332, 726, 986, -1204, 86, -178, + -108, -710, -860, 837, 379, 550, -799, 830, + 1543, 0, -63, -1013, 1051, 1116, 1750, 2197, + 424, -1601, -510, -269, 231, 2672, 150, -694, + 1001, -798, 128, -401, -56, 1168, -274, -233, + 944, 82, 400, -363, 801, 977, -1073, -2137, + 1741, 852, 453, 1430, -34, 2020, -1017, 1377 +}; + +const int32_t StemMultipliers[64] = +{ + 1758050703, 1266450152, 1943571549, 1457436075, 1156726563, 1582068962, 1074888547, 1482969647, + 1339154558, 1434074706, 1328511566, 1488250264, 1372412907, 1586876238, 1327980277, 1456034413, + 1344321574, 1539767512, 1775465622, 1653639072, 1411193849, 1773867739, 1922372773, 1525486538, + 1419605112, 1585501255, 1718198002, 1733141510, 1809603667, 1811370375, 2026824567, 1268800073, + 2144007789, 2147199253, 1650186554, 1219446852, 1615013184, 1393999535, 1136811114, 1628459357, + 1423583182, 2121502736, 2059529823, 1436427782, 1887541213, 1119882731, 1333711284, 1437530810, + 1110102366, 2040201317, 1598316164, 1258624827, 1187163801, 1462682697, 1814006883, 1997045129, + 1247685208, 1236913552, 1822803273, 1626532287, 1504635883, 1227398258, 1770648879, 1977156646 +}; + +const int32_t StemShifts[64] = +{ + -8, -8, -7, -8, -7, -8, -7, -8, + -7, -7, -8, -6, -8, -8, -6, -7, + -7, -7, -8, -8, -7, -8, -8, -8, + -8, -8, -7, -8, -8, -8, -8, -8, + -8, -9, -8, -7, -6, -8, -6, -8, + -8, -8, -8, -8, -7, -7, -8, -7, + -7, -7, -7, -7, -7, -8, -9, -9, + -8, -7, -8, -8, -7, -8, -8, -8 +}; + +const int8_t Dw0Weights[576] = +{ + 93, 54, 127, 6, 84, -1, -4, 47, -43, -7, -15, 6, 103, -5, -16, -57, + 45, 127, -114, 42, 42, 57, 33, 19, 26, 80, -28, -66, 39, -53, -50, -70, + 18, 49, -109, -20, -127, -95, -56, -71, -109, 127, 42, 3, 16, 97, -49, -43, + -62, -97, 22, 21, 92, -18, 42, 37, 27, 127, 4, -95, 40, -82, -71, -81, + 32, 127, -8, -57, -23, -62, 127, 68, -40, -51, 65, 127, 32, 4, -63, -49, + -34, -21, 83, 117, 54, -19, -58, 66, -37, -47, -25, 88, -127, 105, -34, -65, + -5, -47, 127, 10, 20, 67, 1, -90, 127, -46, -21, -127, 5, -127, -63, 22, + -60, 86, -87, 12, -99, 88, -7, -105, -38, -28, 1, -48, 23, -127, -3, -41, + -77, -53, 53, -20, 17, 31, 6, 31, -57, -11, -30, -86, 20, 127, -100, -60, + 6, -56, -54, -127, 45, 8, 87, -125, 22, 10, 127, -9, 22, 77, 127, 120, + -90, 26, 1, 105, 48, 67, -78, 127, 39, 81, 127, -67, 127, -80, 27, -26, + -9, 74, -66, -19, 86, -76, 24, -24, 49, -119, 64, 57, -127, 111, -127, 89, + -44, 29, -97, 108, 127, -58, -64, 127, 45, 8, 9, 5, -37, -38, -16, 7, + 30, 35, -23, -66, -2, 127, -102, -60, -46, -35, -7, -74, 8, 29, 76, 17, + -127, -33, -83, -24, -86, 33, -10, 15, -8, -10, -19, 68, -72, 23, 9, -101, + 85, -38, 45, 36, -127, 37, 127, -121, -58, -58, -101, -77, 61, -74, 78, 66, + 127, -53, 30, -16, -16, -21, -52, 46, -87, 53, -60, -86, 13, -18, -127, 61, + -127, 64, 117, 78, -17, 26, -28, 91, 29, -51, -80, 59, -28, 127, -67, -127, + 25, -27, -5, -3, 94, -127, 19, -86, -29, -101, 20, -43, 31, 31, 127, -25, + -61, -6, -1, -29, 61, -18, -37, 78, 11, 1, 8, 65, 1, -31, 56, 13, + 66, -88, 46, -127, 53, 127, -44, -39, 37, 127, 27, 13, 22, -18, -41, -127, + 126, -9, 77, 18, 64, -82, -34, -127, 59, 127, 36, 17, 25, -126, 57, 50, + -26, -3, 61, -18, -18, 121, -69, 110, -91, 79, 53, -2, 70, -27, 56, 17, + 32, 84, -20, 10, 33, 103, 15, -127, -73, 74, 127, -32, -11, 123, -4, 73, + 54, 36, -45, 32, -22, -11, -32, -29, 36, 69, 30, -35, -127, 26, 24, -37, + 2, -82, 126, -70, 127, -24, 33, 19, -29, -42, -126, -60, -34, 15, -2, 118, + -49, -26, -23, -61, 61, 78, 51, -62, 87, 35, -77, 53, -19, -13, 34, 44, + -48, -11, 41, -11, 7, 112, 10, -127, 14, -68, -125, -76, -67, 84, 33, -127, + 16, -73, -59, 58, -3, -3, -20, -80, -60, -67, -20, -22, 108, -14, -64, -65, + -7, 125, -91, -68, -71, 43, 127, -36, 91, 28, -15, -127, 97, -83, 104, 76, + 20, 19, -100, 22, 31, -47, 58, 74, -107, -52, -71, -83, -62, 0, 117, -127, + 127, -127, 117, -40, -41, -127, 2, -1, 79, 58, 42, -20, -21, 100, -31, -68, + 67, 46, -120, -39, 98, 41, -14, -53, 127, 15, -127, 52, -48, -90, -38, 78, + 68, 44, -127, 15, -42, -33, 11, 14, -127, -10, -81, -107, 3, -114, -33, -100, + 124, -127, 28, -127, -9, -43, 127, 14, 41, -30, -69, -91, -59, -7, -12, 18, + -20, 0, 127, -127, -68, 114, -85, -82, -127, 60, 9, -127, 91, -98, -70, 28 +}; + +const int32_t Dw0Bias[64] = +{ + -1162, -90, 447, -103, -474, 209, 195, -267, + 358, -33, 257, 31, -257, 132, 1916, 598, + -47, -748, -57, 110, -77, -720, -53, 112, + -66, 0, 1173, 415, -19, -304, -1013, -8, + 574, 276, 909, 291, 6, -433, -42, 938, + 75, -178, 315, 745, -92, 432, -598, 1270, + 108, 563, -483, 278, 282, -420, -202, 1373, + 310, -304, -25, 1403, -170, 14, -89, 329 +}; + +const int32_t Dw0Multipliers[64] = +{ + 1258929825, 1623219880, 1948784471, 1360567654, 1147502514, 1933894707, 1227453377, 1994415962, + 1335377519, 1459672822, 1505031947, 1852764399, 1361923102, 1640124628, 1151249273, 1624053192, + 1332213996, 1682410006, 1994678804, 1685554277, 1162760398, 1203838366, 1386329881, 1466102916, + 1128672253, 1333666313, 2039499681, 1466373864, 1093570132, 1391134593, 1666486405, 1882906678, + 1308177162, 1091970486, 1573420313, 1433595570, 1737568847, 1803721641, 1437285080, 1898799171, + 2132123685, 1249621544, 1865953495, 1656949430, 1671543421, 1428663288, 1816605339, 1731828079, + 1172038281, 1480762770, 1645030769, 1126062583, 1936233936, 1341342625, 1748735259, 1465271429, + 1376197610, 2005516511, 1718715586, 1136522442, 1719028686, 1781467449, 1120826928, 1175418339 +}; + +const int32_t Dw0Shifts[64] = +{ + -7, -6, -6, -6, -6, -6, -5, -6, + -6, -6, -5, -6, -6, -5, -7, -6, + -7, -7, -7, -6, -6, -6, -6, -6, + -5, -5, -7, -7, -5, -6, -6, -6, + -6, -5, -7, -6, -7, -6, -6, -7, + -6, -7, -6, -7, -6, -6, -7, -7, + -5, -7, -6, -5, -6, -6, -7, -7, + -5, -6, -7, -6, -6, -6, -5, -6 +}; + +const int8_t Dw1Weights[576] = +{ + 127, 51, -3, -54, 127, -87, -24, 3, -58, 113, -97, 19, -14, -67, -8, -92, + -110, 70, 65, -63, 3, 4, 75, 127, -82, 15, 76, 11, 127, 17, 127, 44, + -97, -85, 54, 72, -65, -127, 26, 86, 26, -88, 36, 127, 29, 103, -95, -127, + 127, -34, -75, -64, 73, 109, 64, 59, 41, 82, 127, 22, 47, 127, 70, -20, + -25, 46, -40, -6, -1, -28, -28, -18, 24, -46, -90, 82, 73, 2, -72, 82, + 45, -56, -80, 127, -127, 127, -52, -25, -92, -14, -47, 5, 43, -11, 18, 114, + -2, 55, 62, 127, -84, -20, 70, -117, -74, 38, 9, 83, 103, 34, -36, -36, + -14, 68, -2, 30, -32, 64, 43, 120, 82, -75, 28, -111, 42, 9, -62, 27, + 112, 88, 46, -14, 47, 17, -69, 124, -5, 60, -12, -54, -48, 127, -15, -49, + 84, 63, 58, -95, -22, -22, 53, -68, 48, -8, -62, -127, -54, 51, 92, -125, + 36, 16, -38, 72, 127, 96, 4, -60, -10, -73, 102, -4, -17, -85, -127, 57, + 127, 96, -82, -61, -26, -127, 89, 49, -8, 13, 7, 1, -113, 57, 48, 63, + 9, -119, -53, -60, 8, 5, 9, 14, -72, 69, -68, -2, 9, 31, -127, 45, + -127, 78, -127, -39, -94, -82, -2, -57, -18, 11, -19, -54, 54, -22, -81, -66, + -18, 70, -67, 61, -92, -38, 32, 14, -127, 22, 8, 62, 52, 16, 2, 4, + 55, 37, -76, -58, 96, 28, 127, 55, 55, -71, -17, -34, -26, 32, 76, -33, + 29, -127, -34, 8, 46, -53, -42, -10, 127, -48, -77, -127, 6, 71, 48, 39, + 25, -33, -12, -64, -30, 0, -127, 97, -2, -10, -36, 54, 44, -29, -67, -34, + -23, -45, 23, 4, -51, 53, 38, -28, -79, -63, -65, 27, 39, 56, -11, -23, + 3, -54, -6, -42, -100, 23, -94, 25, 48, 40, 84, -90, -36, 42, -91, -27, + 9, 43, 127, -63, 48, -69, -42, 121, 45, 34, 60, -94, 6, 44, 62, 12, + 57, -65, -81, -3, -36, -79, 96, -37, 127, 37, -127, 29, -43, 127, 43, -12, + 127, 50, -127, -44, -10, 90, -94, -57, 25, -39, 96, -10, 60, 127, -12, 53, + 110, 127, -127, 30, 32, -74, -122, -2, 44, -66, 38, -127, -68, -3, 40, -61, + -73, -46, -68, -127, 51, -127, -84, -127, 15, 127, 127, -74, 127, 88, 7, 48, + -86, -34, 36, -107, -96, 10, -29, -41, -78, 18, 32, -25, 27, 31, -14, -102, + -34, 39, -119, 75, -2, 39, -3, 21, -48, 73, 61, 82, -127, 95, -14, 45, + 8, -47, -25, -127, 77, 51, -56, 127, -17, -127, 15, 50, -127, 65, -17, -60, + 9, 52, 68, -111, 3, -79, -127, -111, 84, -20, -55, 48, -33, 34, -32, 94, + 22, 102, 85, 113, -82, -43, 27, -106, 21, 16, -51, -16, -51, 8, 110, -29, + -61, -87, -87, 14, 7, 65, -88, -7, 65, -47, -127, 38, 9, -110, -10, -96, + 95, -67, -9, 46, -127, 7, -97, 75, 31, 39, 59, 84, -18, -84, -73, -107, + -47, -99, -14, -68, 116, -63, 62, 110, -23, 109, 48, 112, 28, -13, 41, -127, + -106, 127, -43, -105, 97, 15, 62, 71, 99, 127, -61, 42, -20, 39, 14, -127, + 28, 127, 1, -96, -84, -10, -127, -127, 51, 127, 12, 100, -31, 117, -31, 12, + -39, -65, -64, 55, 82, -36, 47, 121, 127, -1, 64, -34, 17, -31, -127, -127 +}; + +const int32_t Dw1Bias[64] = +{ + -559, 448, -140, 1919, -1015, 1735, 1188, -244, + -699, -987, 267, 682, -402, -1257, 828, -661, + 1725, -633, 173, 587, 2035, 118, -359, 10, + 149, -377, 657, 92, -467, -343, -1265, 1144, + 253, -258, 626, -1222, 1251, -968, 4, 825, + 402, 116, -614, -2528, -469, -1526, 712, 860, + -2118, 102, 1710, 721, -537, -158, -84, -1301, + -1534, 634, -1098, 856, 1309, -771, 366, 1602 +}; + +const int32_t Dw1Multipliers[64] = +{ + 2066458563, 1162890377, 1509136920, 1283378046, 1794111486, 1846960022, 1918334078, 1834874164, + 1152674960, 1722060832, 1666679271, 1605731193, 1246543195, 1154036545, 1451847287, 2027218481, + 1380333188, 1589297932, 1457604833, 1220393771, 2088394005, 2143977739, 1716770758, 1202980098, + 1634581384, 1715523172, 1577929394, 1597295504, 1766374687, 1757192433, 1929300254, 1544714694, + 2129253245, 1657264494, 1977621835, 1085616635, 1650538125, 1651670939, 1292095146, 1842775726, + 1302897773, 2054890500, 1382845244, 1490125828, 1447638491, 1574608642, 2075996719, 1287350457, + 1311355644, 1863720603, 1815814737, 1916635463, 1318763910, 1701012440, 1444284300, 2051063540, + 1324792603, 1075762527, 1418773513, 1556623871, 1464557986, 1787053494, 1681355319, 1826380868 +}; + +const int32_t Dw1Shifts[64] = +{ + -6, -5, -5, -6, -6, -6, -6, -6, + -5, -6, -6, -6, -5, -6, -6, -7, + -7, -5, -5, -6, -7, -6, -6, -5, + -6, -5, -6, -5, -6, -5, -6, -6, + -6, -6, -6, -6, -6, -6, -6, -7, + -5, -6, -6, -7, -6, -6, -5, -6, + -6, -6, -6, -6, -6, -6, -5, -6, + -6, -5, -6, -6, -6, -6, -6, -6 +}; + +const int8_t Dw2Weights[576] = +{ + 120, -127, 51, 47, 82, -57, 127, 96, 58, 35, 53, 53, 56, -79, -127, -127, + 69, 81, -80, -28, -27, -42, -99, 89, -44, 127, -82, 61, 127, 127, -62, -100, + 127, 66, 98, 31, -127, -127, -111, 112, 108, -127, 109, 11, 127, 10, 56, 62, + 127, 20, 91, 49, -9, 127, 89, -111, 62, 127, 12, 127, 37, 81, 69, 60, + 123, -16, 24, -127, -88, 5, 69, 109, 28, 14, -94, -18, 57, -4, -41, -37, + -2, 98, 5, -127, 96, -50, -127, -31, -49, 88, 41, -127, 41, 74, -9, 66, + 7, -5, 25, 37, 37, -46, -127, 14, 38, 77, 14, -127, 22, 29, 58, 127, + 58, 7, 127, 57, 29, -89, 19, 18, -25, 81, -50, 105, -95, -47, -56, -93, + 127, -35, -74, 83, -5, 56, 12, 127, 86, -80, 50, -28, 92, -82, -51, -43, + 98, 77, 6, 22, -125, 20, -26, 33, -61, 32, -99, -1, -1, 83, 10, -119, + 0, 13, 8, -87, -22, 87, -20, 127, -8, 87, -70, -82, 46, 36, -39, 58, + 41, 48, 71, 36, -50, 11, 127, -54, -61, 77, -127, 39, -127, -32, 67, -19, + 50, -64, 66, 24, -7, 14, 11, 46, 74, 33, 52, 28, 47, -127, -43, -73, + -85, -2, -68, 26, 46, -112, -14, 15, -29, 38, -23, -49, 85, 36, -16, -125, + 29, -72, 30, 13, -114, -47, -106, -49, 127, 77, 127, 20, 65, -104, -6, 65, + 56, 19, 101, 48, 22, 87, 44, -110, -4, 48, -43, 21, 8, 1, -86, -72, + -62, -3, 127, -20, -127, 57, -2, 44, 55, -12, -127, -71, -42, 16, -23, 19, + -87, -21, -108, -102, -5, -57, 11, 13, -52, 48, 48, 28, 48, 34, -30, 42, + 60, -81, 127, 20, 78, -123, -51, -75, 62, 71, -8, -40, -20, -103, 18, 15, + 79, 16, 63, 43, 6, -28, 13, -50, -38, -30, -46, -22, -93, -103, -10, -28, + 84, -11, 26, 76, 53, 62, 66, 62, 40, -127, 47, -127, -8, -65, -58, -32, + -4, 16, 50, 2, -69, 21, 66, 36, -80, -8, -8, -95, 115, 71, 35, 37, + 49, -16, 24, -17, -58, 4, 78, -34, -9, 7, -120, -63, -28, -51, -41, 95, + 9, 37, 73, 103, 62, 4, 58, -87, -127, 27, -80, 50, -120, -12, 16, -18, + 34, -58, 107, 35, 8, 95, 109, 34, 42, -11, 20, 9, 47, -30, -11, 54, + -127, 127, -46, 47, 68, -98, -81, 15, -15, 23, -110, -32, 9, 58, -15, -34, + 48, -127, 33, 17, -69, -22, 55, -120, 118, 61, 92, -6, 117, -100, -127, 53, + 108, 59, 97, 69, 127, 76, 58, -98, 6, 52, -43, 98, 80, 55, -95, -73, + 43, -48, 73, -75, -58, 127, 74, 51, 47, -3, -81, -52, 127, -9, -32, -16, + 15, 70, -127, -56, -62, -127, 1, 127, -108, 0, -69, 47, 57, 117, -127, 127, + 117, -51, 88, -127, 124, -64, -3, -118, 58, 16, 55, -72, 63, -127, 10, -53, + 46, 14, 127, 127, 119, 70, 34, -127, -36, 30, -46, 108, -52, -75, -22, -108, + 117, -75, 76, -14, 77, 31, 78, -13, 127, -93, 51, -42, 109, -62, -70, -95, + 14, -1, -85, 37, -127, 33, 13, 68, -127, 35, -127, -62, 58, 124, 87, 34, + 74, 2, 123, 0, -76, -58, 114, 9, 103, -52, 8, -65, -8, -87, -65, 108, + 2, 127, 72, 80, 127, 90, 68, -27, -49, 68, 26, 40, -109, 127, -127, -127 +}; + +const int32_t Dw2Bias[64] = +{ + -3739, 2521, -2201, -477, 393, -2369, -2959, -2603, + -2519, 585, -48, 1409, -2529, 1980, 3330, 2713, + 1145, -1759, 1277, 1427, -160, 3170, 1603, -2115, + 3381, -1793, 2090, 1355, -1647, -2518, 1000, -160, + -3356, 1445, -2335, 190, 518, 2909, 1030, 799, + -1683, -1549, -2307, 1851, -1776, 3084, 318, -3421, + -3366, -1968, -4693, -2756, -2639, -1051, -1412, 2191, + 902, -2892, 1331, -2801, 2577, -171, 1096, 2919 +}; + +const int32_t Dw2Multipliers[64] = +{ + 1116162320, 1347648393, 1483909908, 1717050654, 1499270352, 1736740987, 1597406161, 1821366703, + 2087466627, 1995572357, 1980090031, 1164145146, 1456653956, 1398197405, 2041839389, 1383345075, + 1157736242, 1187658241, 1224627949, 1256920008, 1339344017, 1644544527, 1663668591, 1466403845, + 1580862305, 1732942133, 1242616060, 2140496884, 1088650198, 1681203507, 2092363683, 1421133087, + 1305416161, 1620111380, 1708807939, 1975373282, 1214544052, 1979980912, 2107641973, 1944071924, + 1167713358, 1718823165, 1721044377, 1519732787, 1799775685, 1754422593, 1703511439, 1093992180, + 1264394216, 2056804343, 1261340769, 1401974508, 1400041823, 1211618150, 1348488628, 1796303289, + 2059864172, 1315197510, 1970265718, 1462947089, 1763425008, 1810675549, 1290947725, 1493184131 +}; + +const int32_t Dw2Shifts[64] = +{ + -6, -6, -6, -6, -6, -6, -6, -6, + -6, -6, -6, -6, -6, -6, -7, -6, + -6, -5, -5, -6, -6, -7, -6, -6, + -6, -6, -6, -6, -5, -6, -6, -6, + -6, -6, -6, -6, -6, -6, -7, -7, + -5, -6, -7, -6, -6, -6, -5, -6, + -6, -6, -6, -6, -6, -5, -5, -6, + -6, -6, -5, -6, -7, -6, -5, -6 +}; + +const int8_t Dw3Weights[576] = +{ + 90, 28, 107, -55, -40, 94, -127, 87, 94, 56, 127, -109, -41, 103, 72, 9, + 3, 115, 97, -127, -87, 18, 64, -26, 60, 100, 127, -61, 87, 65, -105, -49, + -49, 115, 100, 92, 13, -92, 127, 39, 112, 108, -91, 124, -100, -2, 109, 36, + -73, 26, 127, 61, -97, 107, 88, 96, -75, 127, 77, 52, -100, -110, 105, 51, + 82, 47, 98, -76, -127, 121, -48, 127, 89, 81, 109, -57, 11, 91, 40, -28, + 14, 110, 99, -87, -21, -127, 87, -27, 45, 58, 86, -90, 112, -14, -20, -94, + 28, 127, 116, 75, 39, -76, 71, 66, 113, 89, -75, 98, -92, -105, 99, -62, + -124, 59, 59, 79, 103, 127, 84, 119, 16, 102, 48, 108, -28, -50, 61, 59, + 127, 127, 98, -75, 3, 120, -103, 88, 51, 83, 87, -122, 51, 115, -28, -127, + -79, 75, 106, -40, -68, 13, 73, -127, 40, 73, 49, -37, 117, 10, -73, -79, + 127, 118, 127, 127, -46, -73, 117, -1, 103, 44, -127, 110, -55, -105, 90, -127, + 9, 112, 85, 110, -127, 114, 98, 126, -75, 104, 85, 127, -124, 18, 120, 82, + 38, 74, 44, -67, -48, -5, -37, 78, 24, -13, 22, -60, -127, 29, 51, 45, + 14, 23, 22, -29, -45, 40, 54, 58, -52, 8, 41, -81, 58, -13, -23, -16, + -86, 60, 98, 37, 4, -9, 23, 127, 38, 52, 28, 34, -95, -47, 39, 31, + -48, 19, -11, 42, -64, 97, 34, 71, -23, -3, 33, 41, 49, -127, 11, 43, + 2, 122, -38, -78, -48, -25, 12, 83, -3, 9, 17, 23, -55, -20, -64, -23, + -99, -18, -15, 9, -102, -59, 66, -16, -21, -28, -5, -106, 43, -53, 27, -15, + 7, -37, 74, -3, 28, -3, 0, 113, 34, 46, 32, 45, -69, -126, 52, -84, + -127, 33, -73, 3, 37, 41, -43, 54, -127, -54, 42, 45, -61, -68, -36, 32, + 58, 91, -5, -100, 23, 10, -16, 79, -23, 9, 18, -54, 13, 1, -45, -124, + -32, -8, 8, -40, 24, -38, 64, -100, -30, -14, 2, -88, 56, 11, -40, -32, + 10, 25, 35, 16, -59, -13, 38, 96, 40, 44, -73, 77, -54, -39, 54, -33, + -13, 75, 7, 76, -65, 80, -6, 66, -15, 26, 41, 44, -127, -31, -27, 75, + 67, 94, 127, -59, -26, 82, -97, 114, 99, 127, 31, -127, -90, 125, 0, 36, + 6, 122, 127, -58, -127, 45, 30, 115, -59, 127, 78, -50, 127, -127, -46, -90, + -17, 97, 127, 50, 37, -98, 63, 117, 112, 109, -113, 127, -103, -1, 91, 16, + -33, 127, 64, 50, -67, 107, 99, 127, -90, 115, 67, 93, -56, -99, 127, 127, + 110, 103, 115, -93, -93, 127, -38, 105, 127, 60, 56, -57, 25, 122, -127, 41, + -127, 127, 116, -83, -71, -2, 92, 43, -127, 74, 71, -115, 124, 37, -33, -127, + 81, 102, 125, 14, 24, -127, 49, 68, 127, 119, -106, 101, -127, -127, 127, -47, + -94, 29, 4, 43, 84, 114, 94, 101, -51, 84, 80, 102, -55, -112, 78, 92, + 119, 106, 93, -127, 21, 85, -102, 92, 96, 71, 30, -48, 3, 127, -119, -76, + 10, 63, 88, -41, -55, -100, 127, -28, -123, 91, 78, -127, 87, 93, -127, -107, + 91, 102, 126, 38, -127, -96, 107, 96, 117, 127, -47, 102, -47, -109, 105, -25, + 18, 119, 80, 127, -61, 115, 127, 86, -18, 109, 127, 45, 40, -6, 101, 62 +}; + +const int32_t Dw3Bias[64] = +{ + -6028, -8794, -3884, 6737, 2882, -4835, 4921, -4708, + -4060, -4589, -2815, 7082, 973, -6258, 1330, 893, + 1640, -4538, -3135, 3798, 4490, 1080, -6756, -580, + 2349, -4045, -5192, 7290, -5103, -728, 4579, 4417, + -2945, -5089, -4955, -4180, -586, 6432, -5815, -10623, + -3861, -6501, 5436, -4359, 5657, 4904, -5036, 661, + 3458, -6278, -3220, -4395, 667, -5835, -2917, -5040, + 3639, -5786, -3631, -5864, 2811, 5032, -3424, -5730 +}; + +const int32_t Dw3Multipliers[64] = +{ + 1084708086, 1456705664, 1237688602, 2104090998, 1415634299, 1195869865, 1409214255, 1808356108, + 1893863004, 2132724060, 1338495001, 1656601672, 1356621688, 1196162788, 1307265086, 1186088330, + 1126801443, 1889703551, 1338295229, 1777816327, 1967249644, 1183864084, 1350675344, 1388667695, + 1596875099, 1227725857, 1109727655, 1944122807, 1630906472, 1638155903, 1480861055, 1671616453, + 1349597840, 1775107244, 1302364131, 2107433755, 1787377027, 1315556971, 1211346433, 1109793785, + 1090461823, 1755056745, 1158269029, 1143576351, 1095883962, 1197541935, 1467606229, 2118901000, + 1744361649, 1339955989, 1950119050, 1906293364, 1948070575, 1572648225, 1275830824, 1708363471, + 1313684785, 1217976695, 1963621820, 2040200827, 1924094236, 1858614011, 1322661193, 1300198418 +}; + +const int32_t Dw3Shifts[64] = +{ + -7, -8, -6, -8, -7, -7, -7, -7, + -7, -8, -7, -8, -7, -7, -7, -7, + -7, -7, -6, -8, -8, -7, -7, -7, + -7, -7, -7, -8, -7, -6, -7, -7, + -7, -8, -7, -8, -7, -7, -7, -8, + -6, -8, -7, -6, -6, -7, -7, -8, + -8, -8, -7, -7, -7, -7, -6, -7, + -7, -7, -7, -7, -8, -8, -7, -7 +}; + +const int8_t Pw0Weights[4096] = +{ + -9, -36, -95, -15, 25, -18, 78, 81, -79, -49, 67, 82, 42, 56, -42, 62, + -109, -72, -13, 25, 57, -35, 68, -53, -98, 127, -9, 14, 16, -29, -41, 14, + -46, -9, -28, 36, -72, 41, 55, -1, 32, -58, 23, -10, 93, -29, -40, 80, + -123, 60, -86, -91, -61, 91, -63, 6, 57, -50, -42, -30, 39, -37, 81, 39, + -9, -21, 7, -86, -33, 40, 127, -28, -37, -27, -7, -84, 4, 1, 47, 52, + -33, -13, 44, -13, -12, 21, -28, -30, 46, 28, 27, -31, -13, 49, 45, 25, + -5, -36, 2, -32, -13, 27, -35, 60, -76, 36, -58, 40, -71, -30, -17, -56, + 31, 49, 26, -70, -10, -26, -34, -20, 51, -34, 52, 19, -69, -33, -27, 49, + -30, -20, 29, -4, 21, 11, 7, 26, 0, -35, 2, 55, -70, -86, -9, -74, + 6, -85, 25, -66, -45, -77, -9, 55, 39, 36, 66, -41, -28, 18, 66, -45, + -31, 39, -4, -60, 17, -78, 35, -53, 127, 6, 34, 51, 17, -8, 18, -16, + -22, 23, 31, -49, -45, -9, -70, 0, -70, -51, -17, 26, -1, -20, -18, -46, + -74, -1, 55, -41, -70, -31, 127, -96, 6, -20, -39, 26, 75, 85, -104, -45, + -5, -6, -67, 46, -48, -85, 69, 42, -43, -32, -45, -2, 13, 22, 1, 60, + -78, -77, 75, 7, -17, 120, -3, -44, -114, -43, -68, 41, 123, 28, -50, 47, + 12, 47, 10, -1, -57, 19, -14, -55, -38, -18, -124, -24, 43, -101, 98, -87, + -53, 88, -14, -12, 13, 46, -2, -27, -26, -43, 66, -1, 57, -16, -31, 49, + 0, -78, -48, -14, 13, 56, -65, 14, 8, 26, -55, -32, 6, -127, -83, 54, + 44, 23, 44, 46, 43, 1, 19, -125, 47, 1, 35, 21, 11, 4, -93, -54, + -64, -60, 27, -39, 8, 61, -69, 27, 77, 42, -7, -108, 24, 29, 15, -7, + 35, 26, 33, -36, 11, -8, -61, -84, -97, -12, 7, -36, 1, -27, 32, -28, + 61, 15, -98, -43, -72, -80, -27, -81, 17, -127, 53, -23, 5, -24, -119, -55, + -67, -83, 42, -7, 36, -35, -28, 68, 44, -46, 44, -14, 14, 106, 37, -109, + 24, -39, -20, 51, 12, 39, -29, -72, -51, -40, -2, -49, -36, -116, -65, 105, + -65, 61, 56, -23, 40, -28, -13, 27, 13, 20, 37, 61, 22, 75, -1, -88, + -113, 2, -88, -76, -25, -127, -64, 95, 83, 50, -123, 9, 85, -50, -19, -3, + -31, -9, 18, -43, -62, 76, 83, 19, 57, -22, -1, -83, 63, -27, -20, 66, + 86, 19, 6, -42, -87, 8, -106, -59, 27, -120, 100, -92, -58, 4, -72, -45, + -2, -92, -10, 34, -35, 8, -41, -113, 50, -39, -44, -3, -4, -47, -15, -84, + -108, -51, -46, -14, -34, -106, 23, 31, 1, -50, -79, 57, 27, -127, 58, 99, + 58, 3, -59, 49, 78, 19, 79, -49, -79, -25, -101, 60, -73, -17, -87, -81, + -32, -95, -27, 81, -18, 13, 27, 122, -48, 15, -66, 41, -62, 68, 72, -97, + -87, -45, -10, 23, -76, -44, -21, -35, -99, 38, -65, -127, -61, -11, 63, -30, + -42, -113, 34, 38, -58, -74, 63, -43, -26, -81, -22, 53, 45, -115, -112, -65, + 11, -40, -10, -20, -12, -8, 0, -75, -96, 81, 60, 9, -83, -22, 21, -13, + -37, -28, 44, 38, -29, -113, -43, -37, 49, 28, 65, 4, -22, -44, 29, 9, + -54, -32, -45, 14, 18, -15, 41, 15, 2, 15, -10, 7, -20, 13, -71, 62, + 12, -56, -9, 20, -127, -31, -51, -14, 13, -58, 48, 9, 50, -62, -18, 19, + 6, -36, 5, -28, -117, -43, -58, -4, -21, 51, 30, -32, 5, -34, 18, 36, + 38, -41, -45, 78, -50, -11, 26, 12, -59, 6, -13, 43, -4, -19, -2, -20, + -20, -25, 127, 16, -14, -46, -105, -78, 48, -19, 63, 94, -75, 11, 4, -93, + -44, 37, -75, -45, 71, 57, -27, 8, -34, -15, 88, 29, 29, -27, -22, -20, + 12, 17, 27, -32, -7, 15, 27, -10, -21, -27, 39, -34, 9, 7, 1, -63, + -3, 24, -48, 66, -109, 56, -64, -82, -21, 21, 27, 25, -19, 40, -23, -44, + 21, 53, 10, 62, 62, -52, -15, -127, 21, 7, -33, 69, -41, 78, -25, 43, + 3, -3, 29, 5, 37, 7, -3, -75, -35, 69, 57, 102, -36, 14, 15, 73, + -37, 112, 31, 90, 95, -29, 22, -41, 3, -52, -28, 22, 56, 47, -27, -14, + 9, 4, 75, 71, 109, -62, 33, -77, 34, -23, -36, 25, 0, -17, -84, 7, + -42, -32, -17, -44, -44, -12, -26, -86, 26, -35, 44, -17, 5, 56, -29, -4, + -23, 5, 33, 49, 65, -28, -102, -27, -79, 0, 14, 14, 56, -126, -29, -13, + 126, 10, 16, -5, 26, 74, 34, -21, -7, -34, -3, 39, 26, 47, -58, -31, + -51, -20, -59, 30, -30, 66, -72, -15, 28, 22, 52, -46, 24, -127, 75, -22, + 61, 0, 87, 60, -34, 110, -2, 50, 60, 22, 55, 62, 5, -39, -82, -40, + -65, -20, -67, -40, 67, -33, 6, 35, -46, 60, -34, -37, 56, -80, 87, -50, + 77, -70, -91, -32, 65, 20, -36, -13, 60, -109, -6, -47, 48, -20, -35, -42, + 20, -21, -32, -127, 67, 33, 39, 89, -57, 29, 54, 44, 8, -47, -13, -12, + -10, 13, 75, 22, -1, -58, 24, -127, -3, -45, 14, 35, 22, 75, -37, 10, + -14, 11, 4, 34, -59, 42, 47, 16, 8, 50, 57, -18, 19, -32, 34, 77, + 7, -15, -43, 39, 59, -14, -71, 6, 86, -18, 61, 31, 42, 75, 31, 60, + 51, 36, -76, -76, 25, -68, -23, -17, -27, 89, 33, 18, 21, -24, 31, 6, + -56, 45, 72, 93, -26, 49, 101, 73, -3, -24, 51, -53, 27, -13, -127, -56, + -62, -42, -36, 62, 80, -1, -53, -20, -24, 44, -33, -69, 24, -40, 27, -121, + 64, 56, 65, 25, 3, -6, 14, 72, 16, -57, 14, -121, 1, 18, -5, -91, + 59, 16, -1, 44, 68, -12, 3, 26, -103, 0, -36, 4, -40, -22, -13, 23, + -8, 66, -29, -29, 20, 43, 9, 68, 50, 85, 45, -8, 5, -110, -94, -114, + -55, 21, 42, 27, -13, 34, -4, 92, -8, -45, 98, -62, 5, 72, -112, -68, + 44, 126, -53, -69, 6, 36, 58, -82, 100, -39, 91, 58, -35, 52, -44, -32, + 126, 56, 7, -6, 9, -4, -13, 13, 0, 63, 25, 127, -19, -49, -8, -15, + -38, -16, 43, -7, 82, -51, 56, -92, -54, -44, -16, -4, -21, -25, -17, -7, + 27, 15, -127, 32, -30, -25, -26, 12, 21, -1, 5, -22, -37, 19, -10, -28, + 15, 54, 10, 26, 9, -72, 16, -59, 6, -60, -47, -30, -19, -55, -68, 28, + -32, -47, 13, 3, -33, -3, -31, -31, 75, 2, 17, -28, -95, 22, -111, -29, + -89, -27, 17, 7, -59, -10, 23, -3, 28, 52, -82, -3, -69, -114, 76, -29, + -48, -75, 8, -39, 23, 116, -47, -74, -57, 61, 20, -28, 77, -22, -61, 74, + -48, 41, 68, 61, 38, -20, -40, 81, 5, -19, 31, 80, -10, -67, -61, -7, + 11, -127, 97, -31, -19, 107, 85, -37, -13, -11, -64, -25, 23, -22, -18, -40, + -31, -44, 80, -7, -70, -5, -69, 75, 105, 65, 45, 127, 66, 102, -71, 42, + -81, 38, -96, -105, 51, -22, -42, 90, -68, -57, -25, -83, -29, 90, -11, 51, + 73, -39, 60, 52, 13, 57, 71, 90, 36, 68, 26, 24, -5, 50, 16, -82, + 109, -25, 36, -44, 55, -20, -71, -61, 9, -2, 116, -45, -16, 81, -74, 81, + -7, 20, -28, 9, 15, -9, 3, -20, 15, -41, 14, -21, 23, -3, -33, 22, + -17, -32, 23, -20, -8, 37, -18, 24, -10, -75, -10, 31, 3, -13, 20, 3, + -30, -70, 32, -12, -41, 60, 31, -10, -55, -14, -25, -31, -33, -42, -21, -21, + 7, 35, -39, 127, 34, 40, -4, -25, 41, -73, 35, -14, 7, 33, 1, 18, + 44, 35, 49, -84, -63, -80, 9, 62, 59, -87, 42, -20, -30, 11, -78, 127, + 99, 12, -92, 17, 78, 28, 30, 71, -55, -55, -120, -29, -21, -79, 23, 22, + -86, -41, -3, -69, -52, -32, 70, -61, 7, -80, 34, -8, -7, 83, -80, 80, + -10, 62, 81, 0, 7, -48, 62, 83, 84, -80, -28, 63, 35, -23, -49, -20, + -79, 3, 48, 77, 34, 84, -62, 20, 49, -55, -47, -34, 35, 4, -20, -85, + 55, -59, -41, 34, -18, -71, -99, 23, -61, -27, -71, -24, 48, -20, 96, -51, + -21, 17, -88, 9, -52, 35, 61, 35, -15, 20, 36, -60, 116, -55, 26, -67, + 28, -1, -78, 36, -127, -48, -93, -83, 3, -47, 29, -52, 24, -55, 25, -122, + -58, -99, 63, -48, -86, -44, 26, 51, 20, -53, 119, -19, 38, -46, 7, -99, + 16, -28, -41, -55, 1, 70, 19, 51, -34, 59, 5, 100, -3, -24, -77, 62, + 15, 17, -5, -49, 25, -77, -10, -86, 67, -37, 38, 51, 19, 69, -10, -63, + -15, -77, -84, -109, -49, -29, -119, -36, -127, -9, -29, 60, -33, -24, -49, 12, + -127, -70, -26, -12, 51, -75, -42, 99, -69, -123, 66, 29, 68, 92, 37, 23, + -40, -119, -103, 124, -27, -60, 5, -18, 102, 4, 78, -83, -7, -73, 37, -1, + -36, 28, -11, 58, -16, 7, -9, 73, -42, -17, -1, 123, -2, 18, 44, -110, + 56, -26, 34, 16, 41, -3, -115, 47, -37, 42, 77, 13, -66, 57, 31, 59, + -11, 65, -3, -49, -25, -99, -118, 58, 75, 74, 24, -13, -112, 127, -25, -20, + -88, -58, 48, -34, 27, 66, 2, -71, 65, -18, 57, -57, 72, 115, -3, -21, + -14, -11, 37, -25, -31, 74, -61, -31, -50, -19, 79, -64, 55, -20, 8, 39, + -50, -81, 5, 72, 75, -46, -63, 37, 44, -75, -104, -117, -3, 91, -46, -24, + -30, -67, -56, 14, -28, -42, -16, -36, 6, -61, -62, 77, 60, 15, -25, 6, + -20, 8, -3, -69, 65, -17, -75, -127, -109, 17, -25, -16, 38, 61, -72, 67, + 28, -15, 79, -34, 47, 72, -53, -63, 7, 33, 43, -30, 13, 32, -4, 9, + 37, -21, 8, 1, 3, -7, -41, -72, 73, 74, -12, -19, -16, 37, 1, -44, + -10, -36, -35, 2, -18, -75, -95, 21, -69, 12, -46, 127, 12, -37, 5, 75, + 33, -67, -37, -44, 66, 46, -96, -60, 2, 35, -39, -43, -109, 78, -106, -3, + 10, -79, -67, 19, 77, -27, -83, -22, 82, -84, 50, -97, 68, 16, -92, -7, + 108, -30, 39, 5, -22, 2, -20, 53, -71, -71, -35, 12, -75, -82, -50, 64, + 28, -26, -100, -4, 7, 53, -29, -54, 30, 39, -106, -62, -10, 13, -60, 20, + -14, 26, -127, -64, -70, 77, -23, 1, -17, -119, 44, 65, -17, 112, -85, 55, + 28, 16, 48, 67, -81, 29, 59, 17, -110, -7, -60, -112, 8, 11, -67, 54, + -45, 76, -39, 42, 43, 66, 20, -48, 54, 3, -73, 5, 17, 80, -36, 24, + -77, -26, -2, 60, -73, 90, -55, -87, 47, -72, 8, 103, 26, -61, -33, -56, + -2, -110, 19, 68, -19, 18, 65, 74, -126, -70, 50, -19, 39, -40, -6, 21, + 53, -21, 27, -19, 48, 28, 94, -44, 28, -72, -72, -32, 84, 5, -64, -33, + 14, 31, 86, -1, -57, 15, 31, 126, -7, -23, 127, 9, -76, -4, -104, 20, + 35, -13, 43, -107, 114, -40, 95, 37, -18, -65, -59, 7, 9, 11, -63, -19, + -43, -74, -34, 82, -34, -81, -24, -57, 7, 2, -108, -25, 77, -40, 52, 6, + 10, 33, -13, 104, -103, 74, -62, 25, -100, 0, -5, 11, 36, -10, 104, 29, + -80, -2, -24, 15, -24, -72, -126, -106, -127, 27, 43, -79, 33, 14, -70, -45, + 40, -101, -29, 76, 114, 7, -68, -23, -50, -25, 4, -38, 0, 89, -12, -31, + -18, -54, 46, -54, 63, 71, 71, -90, 101, -34, -30, 127, 34, 20, 0, 32, + -3, -27, 29, 31, 7, 38, 5, 11, 95, -51, -29, -13, 32, 12, -14, -4, + -22, 13, 37, -84, -10, 63, -28, 33, 9, 42, 49, -62, -31, 29, 78, -41, + -76, 7, -15, -77, 12, -6, 74, 52, -29, -44, 19, 54, 45, 11, -69, -1, + 29, -69, 36, 16, 31, -43, -84, -23, 46, -11, -6, 11, -21, -117, -15, 49, + 3, -20, 16, 5, 105, 31, -33, 82, -14, 33, 93, 72, -4, 63, -60, 45, + 34, -66, -4, 23, -55, -52, -42, 21, -10, -21, 7, 55, 50, 26, -127, 73, + -13, 81, -15, 17, -14, 53, -58, 34, -75, -45, -86, 76, -30, -79, 12, 3, + -69, -4, 53, 44, 66, -47, 41, -36, -37, 23, 45, -81, -20, 33, 35, 82, + -39, -24, -26, 14, 80, -49, 19, -20, -127, 50, 73, 27, -18, 19, -77, 31, + 31, 64, -17, 30, -66, 18, 17, -80, 109, 30, 0, -41, 66, 12, 24, 88, + 15, 80, 46, -4, -6, 59, 33, 37, 110, 31, 9, 46, 27, -37, -21, -90, + 21, -98, 18, -1, 25, 10, -20, -33, 37, 4, -23, -39, -80, 15, -32, 43, + 17, 43, -2, 5, -102, -26, 72, 1, -29, -32, -8, -127, 44, 10, -44, -99, + -41, -54, -5, -31, -14, 9, 38, 49, 19, -100, -9, 58, -5, -31, -8, 11, + 22, -26, 75, 69, 33, -6, -30, -38, 2, -21, 8, -9, -47, -16, 13, 79, + -29, -45, 14, -31, 45, -35, -21, -37, 46, -111, 19, 5, -9, 12, -1, 48, + 18, -22, -70, -12, -1, 127, -14, 29, 1, 49, -40, -28, -28, 53, 32, -18, + 52, 23, -32, 23, -20, 8, 67, 18, 47, 10, -1, 11, -16, -7, -62, 20, + 28, 22, -44, -23, 17, -4, -115, -87, 26, -45, -102, 3, -83, 62, 127, 103, + -2, 28, 48, 33, 6, 100, -75, -82, -53, 78, 34, 117, -115, 13, 4, 33, + 20, -27, 22, -9, -25, -66, -25, 29, -47, -81, 75, -32, -94, -4, 54, 36, + 119, -96, 52, 38, 77, 20, -4, -47, -120, 52, -124, -31, -36, -46, -108, -23, + 65, -90, 69, 93, 4, -31, -20, 29, 24, -64, -15, 59, -71, 48, -2, -55, + 25, -39, -1, 36, -13, -17, 38, -26, 33, 15, 42, -41, 0, -64, -17, 20, + 14, 25, 40, -59, 38, 80, -35, -23, -66, 5, 28, -29, 66, -31, -66, 7, + -84, 28, 20, 46, -42, -63, -103, -10, -34, 3, -127, -88, -21, -26, -32, 64, + -52, -65, 61, -10, -58, 127, -88, 80, 2, -19, 47, 88, -18, 30, -7, 2, + 126, 35, -3, 105, 29, 77, -6, 53, -18, -37, 80, -66, 6, 13, -113, 79, + -79, -127, 88, -2, 48, 52, 82, -75, -75, -70, -52, -68, 32, -60, 92, 94, + -83, 4, -34, 12, -25, 56, 64, 17, 22, -52, 56, -7, 25, -83, 18, 112, + -93, 57, 49, 61, 2, -30, -112, 127, 48, 10, 34, -31, -19, 6, 27, 110, + 96, 38, -40, 116, 88, 87, 20, 43, -79, 38, -57, -123, 21, -2, -105, 22, + -22, 11, 19, 38, -79, 53, 25, -37, 96, 39, 16, -91, -21, 45, 10, -72, + 96, 68, -67, -10, -53, 16, -28, 72, 10, 97, 30, -41, -24, 44, -84, 74, + 26, 13, 71, -13, 40, 37, -35, 16, 34, 19, 10, -23, -7, 2, -12, 2, + -6, 61, 15, -26, -23, 21, -59, -45, -9, 3, -127, -8, 42, -12, 33, -16, + -29, 17, -62, 20, 10, -5, 42, 11, -10, -34, 44, 21, 2, 36, -29, -37, + -34, 12, -36, 38, -12, -14, -22, -8, -27, -45, -21, -22, -3, 50, 15, -35, + -3, 32, 15, -79, 51, 41, 31, 53, 88, -66, 11, -50, 38, 14, 17, -14, + 9, 11, -69, 61, -4, 13, -11, -30, -36, -8, -25, -11, 108, -55, 6, 51, + 28, -42, -127, -106, -3, 18, -2, -61, -20, -26, -39, 36, -2, 35, -18, 58, + -42, 16, 20, 22, -110, 35, -105, -27, -27, -42, -25, 87, 18, -70, -23, -60, + -52, -65, 5, -2, -72, -19, -4, -43, 35, -26, -16, 1, 74, 29, 55, 0, + -84, -67, -102, -7, 5, -61, -7, -84, -5, -22, -24, 20, -15, -27, -5, -57, + -34, 27, 44, -84, 68, 80, 13, -51, 45, -17, -11, 43, 11, -13, -13, 41, + 45, -32, -4, 67, 127, -42, -40, 99, 4, 32, 37, -6, -70, 26, 25, 75, + -66, -30, 31, 53, 28, -68, -1, 11, 17, -127, 8, -26, -4, -56, 76, -2, + 42, -5, 17, -24, 35, -10, 12, -61, 37, 78, -65, -78, 5, 74, 46, 47, + -76, 8, -70, -16, -6, -55, 69, -126, 12, -35, 85, -63, -15, -38, 57, 9, + 6, -51, 17, 13, 17, 28, -38, 42, -35, 70, -37, 35, 0, -12, 15, -47, + 20, -23, 36, 30, 63, 42, 72, -22, 71, 62, 111, 87, 58, -2, -14, -23, + -10, -22, -28, 2, -31, 14, 20, 47, 38, -9, 11, -2, -23, 98, -48, 13, + 47, 106, -20, 38, 31, 82, -11, 19, -31, -63, -115, -86, -24, 10, -29, 72, + 13, -84, 43, -5, -79, -101, 59, -58, 21, -73, -64, -127, 21, 26, -31, 15, + 8, 3, 24, -46, -14, 72, -58, -43, 22, -61, -30, -61, 31, 74, 19, -69, + -17, -76, -58, -15, 5, -81, -19, -56, -21, -52, 81, -35, -1, 22, -36, 114, + 11, -44, 61, 40, 20, 25, -33, 60, -64, -67, -71, -6, -63, 60, 39, -80, + -56, 33, 57, -9, 29, -46, -37, -89, -125, 113, -1, 96, 127, 8, 3, -1, + -5, -72, 12, 15, 3, -19, 22, -24, 0, -51, 31, -47, 1, 7, 11, -15, + 54, -45, -78, 56, -91, -52, 32, 67, -16, -41, -56, 72, 39, -81, 47, -19, + -127, -20, 82, -37, 16, -57, 33, 2, -46, 58, -29, -85, -15, -112, -71, -11, + 3, -15, 3, 12, 20, 61, -38, 67, 15, 37, -30, -44, -34, -10, 3, 23, + 12, 19, 65, 14, 29, 57, -29, 48, 4, -7, -39, 19, 32, -54, -57, -14, + -47, -79, -30, -3, 29, 32, -30, -14, 17, 34, -42, -13, 6, -49, 22, -24, + -52, -26, -28, 7, 36, 20, 82, -127, -6, -53, 60, -48, -66, 11, 21, 36, + 14, -7, -11, -19, 12, 46, 10, -52, -9, -62, -6, 56, 30, 27, -20, 47, + 23, -3, 33, -72, -19, 22, 29, -18, 78, 7, 5, 52, -59, -4, -7, 2, + 51, 32, -1, -21, 14, -3, -10, -101, 27, 7, -74, 4, 38, 38, 83, -67, + -3, 63, -60, -43, 52, -21, -29, -31, -28, -73, -127, 62, 7, -14, -106, 25, + 30, -75, -35, -62, 30, -47, -19, -27, 32, 75, 15, -100, -49, 43, -67, -62, + 53, -74, 26, 75, 19, -84, 43, 62, -36, -127, -24, 32, 8, 43, -1, -7, + -22, -17, -40, -40, 41, -6, 62, 53, 55, 39, 93, -50, 16, -76, 89, -37, + 40, 13, -12, 26, 80, 53, -15, -85, -61, -34, 13, 62, 14, -11, 15, -15, + -48, 21, -2, -45, 37, 10, 1, 42, -22, 29, 79, -61, -31, -55, 39, -36, + -127, -43, 65, 20, 68, -101, 68, -43, -115, -57, -55, 30, 74, 69, 51, 36, + -27, -98, -47, 30, -44, -45, -58, 23, 0, 29, -63, -94, -55, -3, -71, 60, + -2, -48, -100, -61, 56, -20, -41, 101, 16, 70, 17, 47, 26, 40, -25, -59, + 14, 19, -31, 59, 6, 17, -91, -45, -68, -20, 18, 40, -81, -26, -22, 46, + -23, 92, 27, -4, -34, 10, 47, -37, -38, 58, 21, 57, 11, 71, -23, -21, + -54, 59, 57, 127, 33, 0, 4, 98, 37, -75, 24, -52, 65, 15, 12, -67, + -41, 60, -37, -9, 1, 24, -97, 41, 36, 23, 61, 84, -14, 8, -37, -20, + -112, -8, -65, -58, -15, 7, -61, 55, -40, 81, -58, -27, -6, 97, -119, -53, + -27, 14, 8, 60, -76, 45, 24, 1, -63, -36, -3, -55, -91, -29, -45, -33, + -20, -71, -9, 33, 36, -18, -16, -4, -34, 58, 54, -127, -29, -19, -61, -1, + -60, 69, -45, 105, -90, -31, 23, 21, -18, 14, 31, -16, 68, 35, -31, -39, + -40, -17, 20, 58, -7, 39, 28, 0, -14, 1, 66, -8, -53, -84, -21, 22, + -14, 40, -35, 7, -18, -76, 16, 8, -8, -50, 39, 107, 40, -61, 52, -77, + -47, 19, -75, -25, 35, -3, 23, -55, -55, 34, -41, 69, 59, 2, -20, -22, + -46, -59, 113, 14, 23, -21, -5, 44, 37, -61, 43, -3, 10, -9, -20, 123, + -12, -9, 59, 41, -66, 12, 5, 46, 8, 48, -9, 15, -127, 4, 36, -4, + -127, -81, -65, 65, 65, -3, -6, 88, 46, 53, 1, 112, 32, -47, 18, 50, + 27, -111, -58, 82, -82, -9, -69, -79, 15, -111, 82, 83, -108, 83, 3, 3, + -35, -83, 59, 63, -44, 8, 26, -16, 80, -8, -69, 86, 12, -39, -123, -32, + 25, -10, -12, -41, -97, -71, 24, 52, -89, 103, -16, 17, -3, 6, -112, 46, + -96, -29, 4, 74, 62, 82, 1, 18, -49, -57, -76, 24, 20, -4, 4, -9, + 26, 0, -68, 0, -99, -26, 28, 49, 24, 76, 47, 17, -37, -77, -6, -83, + 9, -38, -47, -127, -64, -49, -101, -44, -15, -16, 76, 26, 54, -68, -122, -3, + -9, 8, -86, 33, -14, -16, -2, 51, 65, -30, 21, 58, 26, -7, 13, 12, + 24, -16, 24, -55, -59, 23, -53, -57, 20, 34, 75, 88, -56, 1, 0, -51, + -22, -56, -37, -20, 18, 52, 10, 22, 23, -8, 81, -37, 127, 50, -34, 66, + 60, 59, -59, 35, -7, -57, -15, 38, -30, -61, 12, -38, 17, -42, 42, 83, + -17, -24, 13, -62, 5, 75, -18, 29, 76, 41, -9, 48, 65, 44, -34, -41, + -60, -8, 125, 41, 26, -37, -70, -25, -51, -96, 24, 15, 30, 45, -26, -49, + -43, -14, -46, 48, 69, -52, 34, -49, -18, -49, 108, 2, 16, 48, 103, -48, + -103, -127, -10, -78, 50, 51, -33, -44, -23, 18, 76, -36, 0, -5, -19, 53, + -77, 46, 27, -38, -30, 33, -122, 30, 35, 20, 20, 1, -23, -48, 12, -13, + 42, 32, -38, 34, 35, -26, 59, 26, 34, 5, -54, -48, 27, -36, -66, 34, + 36, -13, 33, 50, -14, -22, 41, -6, -3, -25, -50, -7, -13, -2, 72, 49, + 59, -3, -52, 58, -19, -127, 1, 10, -56, -18, -38, 35, 57, -62, 14, 24, + -27, -74, -13, 65, 25, 96, 67, -19, -9, -34, -29, 117, 29, -25, 41, -28, + -36, 59, 16, 6, -32, 52, 94, -3, -74, 17, -45, -18, -5, 127, 3, 59, + 24, -72, -61, 83, -43, -52, -6, 31, 41, 9, -64, -56, 41, -28, -55, -77, + 63, 16, -2, -30, -33, 1, -30, 53, 35, 18, 15, -87, 91, 53, -33, 121, + -33, -12, 79, 31, 44, 96, -32, 39, -11, 34, 35, 1, 31, 33, 2, 42, + 22, 14, 127, -44, 53, -10, 56, -10, 46, -4, 23, 25, -37, 40, -9, -9, + 20, 30, 24, -39, 49, -7, -1, 28, -53, 6, 11, -34, -27, 50, 44, 36, + 99, -44, -20, -29, 34, -18, -23, -46, 80, -35, 35, 1, -16, -28, -55, -8, + -18, 4, 19, 24, 84, -6, 2, 9, 65, -60, -17, -43, 36, -5, -60, -7, + -12, -70, 32, -127, -95, -8, 20, 35, 63, 65, 44, 68, 40, 42, 22, -42, + -61, -80, 55, 1, -64, -17, 37, -3, -106, -60, 55, 44, 30, 13, -25, 41, + 14, -40, -7, 0, 32, -36, -65, 19, -5, -54, 12, -22, -12, 56, -94, 83, + 70, -81, 62, 80, 27, -65, -38, -23, -28, 40, 31, 1, -48, -80, 1, 4, + -67, -7, 55, -92, -41, -100, -21, -89, -95, 18, 23, 24, -44, -2, 26, -16, + -33, -79, -41, 29, 20, 12, -45, 48, 50, 127, -25, 38, 55, 14, 65, -24, + -5, 18, 75, 4, -6, -57, 90, 60, 107, -18, -53, 46, 98, 46, -61, 30, + 35, -15, 40, -17, -58, -96, -31, -79, 24, 67, -57, -35, 22, 18, -44, -35, + -40, 101, 13, -75, 13, -102, -13, -105, -58, -24, 18, -52, -116, 28, 49, -5, + -76, 69, -2, -27, -22, 57, -23, -36, 69, 35, -5, -58, 57, 34, -79, 12, + -2, 47, -68, -63, -78, -105, -9, 19, 84, -6, -8, 16, 37, -27, 51, -48, + -58, -91, -15, 79, 6, -39, -25, -127, 45, 9, -25, 47, -24, -113, -17, -80 +}; + +const int32_t Pw0Bias[64] = +{ + 1185, 468, 1139, 2310, 221, 3620, 1816, 3141, + 4794, 1930, 115, -2161, 625, -644, -1738, -679, + -1735, 3134, 272, -2780, 642, 332, 3189, 3180, + -662, -296, 1357, 3443, 410, -1349, 3707, -1124, + -1100, -1541, -325, -1031, 1268, 1804, -2070, -1729, + -145, 1422, 29, 1235, -1236, 1364, 1910, 373, + 1950, -944, 3010, -1357, 1240, -1319, 367, 1454, + -2262, 360, -1349, -2412, -1553, 387, 200, 3879 +}; + +const int32_t Pw0Multipliers[64] = +{ + 1392260978, 1140456844, 1902230259, 1914975110, 1676888291, 1647435392, 1487160937, 1275154854, + 1283542335, 1863741568, 1707293050, 1225218708, 2144579172, 1946981588, 1377741916, 1326899776, + 1936214238, 1230806448, 1559902480, 1895622196, 1076839277, 1076014931, 1950805641, 1542857979, + 1266132911, 1820694103, 1087228963, 1763587330, 1435767534, 2129464423, 1548430430, 1734453379, + 1688583461, 1201633611, 2011419735, 1643086221, 1584491393, 1110018629, 2017403639, 1520314698, + 2022040850, 1151714747, 2130913925, 1231884047, 1383825748, 1773532328, 1771861922, 1428246386, + 2121787734, 1084407619, 1249783249, 1585906442, 1961026160, 2103657436, 2099865731, 1405601405, + 1201723789, 1381918928, 1954376442, 1936384846, 1259396337, 1108024843, 1606491499, 1999413373 +}; + +const int32_t Pw0Shifts[64] = +{ + -9, -8, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -8, -9, -9, -8, -8, + -9, -9, -9, -9, -7, -8, -9, -9, + -9, -9, -8, -9, -9, -10, -9, -9, + -9, -8, -9, -8, -9, -8, -9, -9, + -9, -8, -9, -8, -8, -9, -9, -8, + -9, -8, -9, -9, -9, -9, -10, -9, + -8, -9, -9, -9, -8, -8, -9, -9 +}; + +const int8_t Pw1Weights[4096] = +{ + 16, 32, 26, -21, -13, -2, 22, 2, -59, -59, -100, -21, 34, -3, 32, -20, + -12, -47, 1, -72, -99, 16, -17, -8, -14, 71, 42, 29, -6, 43, 85, 25, + -28, 34, 62, -32, 29, -75, -48, 57, -59, -23, -71, 23, -59, 7, 127, 54, + 91, 62, 9, 2, 0, 63, -55, -20, -58, -47, -66, 15, 34, -40, 46, 42, + -62, 76, -30, -8, 18, -15, -82, -83, 17, -95, 57, -36, 51, -35, 19, 32, + 8, -16, -91, 9, 50, -13, -53, -31, -43, 24, 127, 17, 8, 70, -62, 44, + -36, 53, 30, -43, 12, 34, 4, 127, -62, -1, -7, 42, 21, 38, -38, -18, + 28, 46, 11, -19, 24, -2, -23, 15, 75, -8, 23, -80, -52, 39, 13, 37, + 60, -53, -91, 27, -127, 1, -64, 84, -6, -33, 40, -14, -1, -43, 33, -37, + 25, 98, -58, -32, -80, 70, 1, 43, -76, -6, -102, -26, -4, 101, 43, -64, + -55, 4, 106, -75, 62, 16, -6, -33, 66, -51, 4, 57, -54, 5, -34, -47, + 11, 77, 24, -40, 96, 50, -45, -72, -14, 28, -90, 37, -42, 52, 99, 90, + -47, -29, 31, 11, -21, 108, -33, 22, 52, 39, -14, 57, 21, 4, 51, -11, + -46, 16, -26, 25, -71, 8, -2, 1, 27, 7, -46, 27, -70, 24, 55, 5, + -49, 22, 1, -30, -59, -58, -61, 86, -24, 51, -28, 27, 8, 52, 21, 60, + -6, -51, -33, -37, 17, 41, 70, -11, -27, -37, 25, -9, -127, -26, 18, -7, + 18, 109, -29, -15, 39, 39, 19, -16, -10, -26, -3, 62, 127, -28, -65, -58, + -28, -98, 72, 47, -36, 25, 64, 6, -22, 69, 63, 67, 70, -56, 61, 11, + -41, 49, 80, 72, -2, -57, 64, 21, 12, -6, -23, 58, -48, -60, -5, -20, + -49, 66, 10, 37, 34, -36, -37, -50, -40, 23, -46, -12, 87, -99, -122, 0, + -20, -23, 27, -52, 49, 84, 15, 32, 0, 5, -24, 8, -42, -22, 32, -21, + 20, 8, -33, -52, -53, 22, -8, 67, -41, 54, -50, -5, 65, -3, 55, -1, + -38, -19, 1, 14, 28, 31, -2, 10, -14, -56, -43, 51, 55, 61, -30, -67, + 78, -34, 35, 43, -64, 72, 17, -62, -11, -68, -24, -12, 127, -58, -91, 6, + -28, -79, -122, -80, 29, -3, -12, -35, -62, -3, -47, 45, 63, 55, 36, 2, + -86, -23, 9, -45, -23, -25, 80, 61, 7, 15, -127, -14, 19, -9, 73, 44, + 107, -38, 15, -42, -68, 29, 14, 1, 94, -85, -106, -112, -35, -67, 11, 18, + -37, 53, -47, 1, 34, 37, 15, 17, -38, 62, -42, 18, -77, -39, 83, -49, + -32, -106, -9, -8, -1, -69, -16, 57, -103, 58, 29, 7, 9, 47, -22, -80, + -103, -59, -52, 55, -107, -4, -50, -94, -77, 80, 81, -49, 34, 72, -78, 41, + 67, 106, -88, -74, -47, -6, 77, 17, -36, -103, -79, 33, -31, 20, 1, 127, + -3, -24, 68, 16, -85, -36, -9, -53, 41, -61, -34, 20, 2, 30, -12, -121, + 17, 20, -92, 73, -5, 28, 42, -11, -4, -70, -44, 25, -31, 33, -108, 2, + -17, -44, 70, 127, -57, 68, -45, 20, -1, 23, -71, -56, -8, 35, 57, 77, + -5, 23, -35, -50, 8, -68, -23, 42, -71, 58, 22, 56, -33, -57, 1, -38, + 57, 20, -18, -40, 49, -29, 11, -86, -4, -127, -19, -63, -98, 54, 115, -86, + -72, -30, 39, 22, 75, -39, -54, -44, 7, 9, -63, 60, -73, 50, 13, -6, + 100, -12, -46, -74, -86, -6, 91, 27, -54, -42, 13, -6, -62, 33, -45, -3, + -41, 72, 2, 35, 93, 29, -42, -22, 2, -54, -10, 34, -14, -7, -64, -38, + 71, 71, 68, -8, 96, 81, 32, 7, 99, 40, -43, 127, -94, 69, 4, -10, + 22, 41, -17, -70, 55, 40, -15, -53, -127, -108, 35, -20, 14, -57, -32, -13, + -66, 12, 96, -106, -29, -20, -57, 83, 28, 83, -49, -8, 23, -96, 18, -89, + 47, 41, 93, 46, -78, 35, -3, 41, 12, 26, 62, 6, -2, 12, 2, -68, + 5, 96, -4, 7, 49, -96, 30, -101, -75, -69, -84, -17, -12, 54, -14, -7, + 37, 23, -25, -38, 12, 50, -8, 54, 20, -29, -49, 70, -70, 92, 6, 50, + -16, -33, -13, 82, 23, -37, 41, 93, 38, 115, -54, 18, -124, 95, 99, 28, + 24, 30, -8, -114, 1, 86, 23, 22, -36, 37, -40, 28, -51, -77, -62, 9, + 96, -84, -50, 11, -22, -12, 5, -77, 37, -127, -101, -54, 26, 73, 105, 17, + 20, -4, -17, 28, 52, 82, -4, 86, -31, -78, 9, -26, 73, 9, -15, 48, + -78, 44, -11, -61, -43, -100, -63, 127, -10, 3, -116, 79, 37, 0, 50, 38, + -36, 95, 33, -2, 23, -28, 19, 123, -78, -71, -59, -26, -68, 49, -13, -87, + -88, 13, 1, 19, 18, -28, -40, -51, 62, -38, -42, -34, 1, 33, -44, 57, + 27, -96, 44, -92, -28, 53, -24, 25, 10, -30, -12, -10, -42, -10, 34, 13, + -127, 13, 40, 35, -92, 68, 67, 39, 18, -14, -1, 14, -72, 36, 11, 38, + 43, -88, -46, -101, 31, -48, -27, 70, 66, 56, -6, 96, 22, 63, 0, 23, + -14, 15, -8, -10, 21, -30, 85, -64, -85, -46, -66, 34, -56, 12, 25, 51, + -40, -46, 67, 52, 50, -1, -65, -35, -2, -17, 45, 9, -19, -64, -31, 70, + -48, -3, -7, -18, -19, 40, 56, -127, 0, 14, -4, -52, 1, -79, 23, -54, + -2, -45, 54, -50, 33, 44, -6, 4, -26, -32, 90, 61, -12, 5, -55, 1, + -50, 12, -59, 37, 16, 25, -65, 109, -59, 4, 36, 17, 33, -40, 4, 35, + 23, -115, 71, 30, -4, -86, -2, 52, 68, -63, 59, -26, -23, -8, -8, 47, + 28, -38, -35, -28, -85, 0, -33, 73, -35, 42, -94, 59, 5, 90, 69, -60, + 5, -49, -27, -58, 50, 127, 55, 40, -67, -57, 15, 34, -72, 54, 21, -7, + 45, -3, -71, -43, 31, -22, -1, -28, -45, -15, 32, 2, -9, -35, -36, 11, + 12, 28, -70, -80, -46, 97, 41, 2, -37, 19, 8, -30, -16, 31, -62, -1, + -62, 104, -36, -54, -95, -60, 69, 37, -4, -1, 33, 64, 0, 127, 107, 29, + -36, -70, 25, -97, 52, -24, -25, 87, 9, -21, -122, 92, -1, -27, 45, 98, + 46, 3, -16, 41, 55, 29, 8, 66, 7, 38, -45, 0, 44, -59, 81, 109, + -78, 17, -76, 8, -36, -18, -78, 10, -32, -98, 107, 71, 30, -23, -53, 58, + -77, 78, 106, 85, -127, -113, 63, -75, 64, 24, -86, 126, -30, 62, 86, -62, + -6, 44, -75, 32, 22, 8, 47, 93, 86, 93, -2, 18, -25, -32, -44, 63, + 52, -52, -77, -105, -35, -74, -14, -71, -12, 3, -102, 4, 24, 19, -31, -60, + -27, -52, -62, -83, -12, -41, -14, 5, -2, -119, -47, -39, 57, -25, -82, 47, + 23, 40, 70, 35, 40, 56, -3, -41, -2, -74, -32, -19, 10, 26, -58, 125, + 14, 2, -32, 9, 22, -120, -64, -20, 53, 6, 21, 11, 46, 35, 83, 76, + 75, 30, -47, 29, -43, 4, 15, -39, -51, -8, -117, -37, 54, 66, -127, 60, + 77, -33, 100, 48, -20, 35, -30, 85, -36, 6, -32, 47, 22, 42, -90, 16, + -44, -35, -14, -43, 78, 21, 41, 7, 7, -127, 36, 21, -28, 7, 37, -30, + -72, -28, -19, -51, 23, 20, -6, -26, -66, 30, 45, 84, 65, -46, 19, -55, + 112, 11, 5, -6, 24, 125, -49, 63, -5, 28, 5, 13, -92, 69, -49, 62, + -42, 24, -30, -68, -38, 69, -26, -6, -1, -12, -15, 33, -11, 54, -88, -63, + 50, -75, 23, -30, -127, 10, 66, -30, -48, 6, 7, -24, -47, -17, 93, -6, + 22, 109, -3, -75, 21, 64, 84, 94, 76, -23, -11, -22, 21, 106, 57, -18, + 89, 64, 61, 4, -88, 73, 22, -76, -27, 13, -25, 48, -68, -77, -11, -66, + 116, -6, 82, -20, 59, 73, 19, 14, 25, -12, 0, 76, 27, 2, -26, -14, + -17, 21, 25, -68, -46, -45, -58, 6, -103, 14, 24, 6, 80, -52, 52, -7, + 122, -51, -1, 28, 2, -28, -5, 87, 10, -15, 39, 29, -35, 69, 47, 16, + -22, 55, -13, -63, 41, 28, -42, -40, 97, -60, -7, 15, 127, -6, 70, -35, + -10, 61, -127, -104, 100, 19, -8, 101, 78, 31, -3, 113, 90, 68, -29, -23, + 35, -50, -15, -24, 66, 1, -22, -49, 69, -79, -79, 104, -55, -107, -52, 30, + 38, 6, -8, -11, -106, -8, -36, 35, 23, -122, 21, 52, 7, -73, 34, 11, + 103, 43, -40, -17, 33, -35, 95, -98, -50, 25, 19, -48, 17, 23, 80, 5, + -60, 113, -84, -2, 41, -9, -5, -89, -84, -14, 0, -40, 24, -35, -72, 12, + -16, -44, 113, -80, -40, -85, 59, -1, 82, -28, -10, -101, -26, 9, -25, 20, + -71, 3, -74, 48, 57, -36, -107, 18, 65, -28, -3, 28, 14, -14, 34, 79, + 115, 19, -21, 0, 28, -5, 79, 32, 54, -127, -8, -54, -21, 67, 31, -32, + -6, -23, 20, -11, -91, -23, -3, -91, -127, -66, -2, -35, 74, 42, 7, -5, + -32, 74, 9, 28, -5, -27, -70, -50, -6, 24, -35, 12, 37, 18, -10, 8, + -20, 71, -43, 70, -10, -8, 42, 10, -8, -12, -33, 3, -2, 7, -19, 25, + -85, 49, -14, -47, -62, -23, 62, 22, 28, -11, -10, 73, 25, -63, -18, 21, + -33, 86, 0, 79, 75, -80, 80, 90, -118, 40, -20, 109, 48, -2, -9, -79, + -32, 2, -38, -35, -3, -18, 28, -11, -79, 25, 35, -43, 0, 35, -77, -80, + 28, 48, -61, -48, -117, 11, 10, 3, 127, 68, 57, -32, -112, -51, 108, -19, + -12, 21, 113, -64, 23, 24, 45, -35, 51, 108, -5, 27, 5, 53, 75, 14, + 4, 39, 11, -76, -29, 124, -65, 6, -79, 33, 33, 103, 104, -2, 43, 92, + 16, -78, -40, -16, -127, 40, 36, 104, 52, -76, -50, 35, -47, 39, 15, 29, + -92, -18, -39, 29, 109, 75, -36, 61, -30, -80, -71, 40, -28, 23, 3, -39, + -40, -33, 65, -40, -22, -17, -11, -34, -123, 19, 2, 25, 6, -42, -16, 47, + 24, -42, -51, -55, -101, 81, 56, -16, 77, 105, -21, -56, 48, 14, -45, -25, + 70, -22, 2, -34, -36, -46, 69, -1, -28, 73, 97, 12, -5, 37, -3, 97, + 6, 7, 7, -55, -19, 61, -36, 70, -54, 30, 2, 22, 33, 15, -51, 10, + 12, 29, 43, -16, -45, 20, -10, 14, -19, 9, -42, -127, -9, 45, 77, -58, + 10, -5, -35, -11, 26, -13, -83, -35, 17, -52, 56, 36, -39, 33, -33, 25, + -29, -60, 55, -32, 43, 0, 16, 24, 35, 21, -53, -119, -65, 35, -29, 65, + 41, 39, -52, -43, -34, -25, -17, -127, -24, -55, 54, -8, -5, -1, -23, -36, + 59, 41, 23, -14, -39, 15, 22, 21, -61, 6, 28, 31, 7, 33, 13, -46, + 56, 8, -122, 35, 23, -52, -22, 4, -66, -34, -39, -125, 7, -92, 104, -49, + -44, -85, -110, -105, -20, 49, 51, -108, 24, -49, -25, -17, 99, -120, -11, -80, + 4, 105, 52, -56, 9, 16, 55, -12, 88, -13, 50, 127, -37, -80, 25, -55, + -49, 91, 19, -65, -34, -32, -66, -2, -28, 29, 13, 70, -52, 42, 0, 30, + 23, 9, 105, 59, 70, 57, -15, -49, 50, 6, -35, -116, 86, 54, -17, 0, + 31, 10, 69, 100, -25, -32, -9, 24, -24, 7, 18, 30, -21, 10, 6, 25, + 29, 49, 53, -42, -40, 14, 120, 63, 13, -16, 13, 3, -58, 84, -44, -8, + 33, -2, -22, -47, -13, 9, -33, -19, 35, 1, -38, -127, 36, -44, 50, -79, + -101, -23, -55, -70, -52, 36, 38, -74, -30, 61, 63, -59, 9, 28, -67, -39, + -47, 58, -74, -12, -23, -58, -49, -42, 86, 0, 60, 20, -77, 127, 27, -80, + -102, -73, 55, -23, -36, -66, 34, 114, -7, -20, 47, 83, 10, -52, -66, 75, + 5, -41, -100, -41, 62, -24, 106, 71, -74, -14, -33, -87, 87, 32, 21, 33, + 53, -8, -8, 53, 43, 57, -70, 67, 19, -93, -14, -71, 110, -62, 59, 16, + -83, 7, -78, -8, -119, -49, -127, 59, -75, -84, 45, 82, 15, -10, -27, -61, + -46, -87, 76, 63, 111, -16, -25, 68, 9, -103, -50, -2, -127, 53, 27, 34, + -45, -58, -37, -55, -30, -65, -9, -29, 65, 38, 58, 76, 29, 62, -28, 126, + -46, -17, 30, -24, -60, 90, 49, -115, -31, 10, -78, 123, -22, 32, -54, 42, + -79, -22, 75, 19, -16, 7, -27, -71, -96, 82, 5, -32, 103, 98, 23, 36, + 114, 127, 63, -88, -70, 38, -39, -11, 27, 56, 78, -23, 35, -82, -15, 7, + 37, 23, -21, -25, -108, -36, -31, -27, 78, 121, -17, -65, 36, -49, 27, -29, + 24, 17, -3, 74, 45, -65, -47, -17, 56, 2, -30, -59, -37, 6, -58, -3, + -127, -98, 25, -13, -67, -42, -22, -37, -49, 13, -1, -99, -2, -67, 67, 104, + -32, -22, -31, 4, -53, -27, -93, -51, -39, 48, 2, 28, 46, -41, -21, 90, + 32, 63, 21, -60, 55, -62, -1, 61, -4, -13, -53, 10, -68, 71, 69, -46, + -88, 22, 37, 16, -34, 68, -47, 61, -49, -43, 20, 6, 50, -53, -40, -16, + -89, -30, -63, 5, -57, -16, 38, -88, 18, -64, 9, 4, -4, -76, 81, -65, + -21, -34, -84, -33, -53, -45, 19, 16, -49, -12, 115, 40, -78, -9, -52, 5, + 104, 127, 39, 54, 73, 6, 7, -80, 45, 14, -60, 91, 104, -32, -6, 29, + 91, -22, -53, -34, 0, -36, 36, 20, 38, 25, -51, 49, 17, -53, 52, 73, + -65, -13, -35, -40, -17, -100, 15, 12, -8, 64, -62, 30, -2, 29, -54, 38, + 13, 12, -12, 22, 67, 127, -51, 34, -123, -82, 12, -36, 68, 13, -22, 20, + 25, 26, -17, -68, 3, 41, 50, 41, -57, 58, -57, 77, -33, -11, -19, 6, + 41, 37, 68, 65, 38, 86, 111, -24, -66, 27, 84, 21, -66, -57, 127, -106, + 84, -94, -60, 33, -11, -87, -75, -104, -13, 29, 6, 4, 69, 40, 19, -5, + 16, -6, -16, 83, -2, -53, -71, 13, -114, -39, 15, -84, 77, 114, -70, -77, + -11, -16, -34, 22, 3, -72, -105, -33, 30, -7, -24, 61, 40, -68, 20, -111, + -19, -93, -69, 38, 42, 67, 12, -107, -8, -61, 20, -58, 94, -43, 44, 46, + -62, 0, 120, 48, 22, 24, -64, 64, -49, -51, -6, -39, 23, 22, -127, 61, + 22, -18, -40, -12, 103, -2, 110, -29, -23, -36, 61, 14, 53, 21, -76, 21, + -52, 8, 84, 16, 79, -16, 40, 28, 58, -60, -51, -80, 43, -29, -30, -87, + 125, 88, 27, 66, 67, 51, -63, -52, -62, 44, 49, 90, 75, 10, -56, -67, + -5, -30, 22, 4, 82, -2, -58, 58, -75, 27, 38, -94, 20, -26, -19, -88, + -50, 65, 15, 28, -4, -34, 0, -76, 122, 12, -17, 11, -71, 2, -31, -7, + 28, 96, 29, -14, -1, 127, -10, -77, 58, 76, 16, -61, -42, 13, 51, -36, + -62, -56, 52, -66, -101, -22, 4, 12, -20, 11, 22, -26, 30, -27, 11, -32, + 45, 13, -46, -17, 1, -17, -43, 32, -40, -56, -55, -120, 6, 44, 7, 1, + 62, 47, -82, -63, 99, -9, -47, -7, -54, -34, 56, 32, -78, 38, 81, 34, + -7, 64, 18, 40, 37, 69, -127, 22, -3, -27, -1, -38, 37, 25, -64, -2, + -1, -64, -22, -62, -76, -19, 43, 48, -104, 18, 88, -29, -16, -72, -3, 31, + 38, -113, -22, -35, 61, 100, 52, -1, 38, 56, -89, 84, -17, -60, 89, 56, + -64, 33, 4, -18, 63, -114, -71, -8, 81, -41, -71, 35, 38, 10, 32, 39, + 1, 46, 44, -5, 14, 33, -6, -59, -89, 6, -58, -43, -127, -24, 88, 45, + -64, 41, 28, -43, 91, -71, -119, -39, -42, 15, 93, 6, -2, 33, 19, -40, + -73, 57, -2, 29, -111, -45, -6, 15, -20, -8, -68, 127, 69, -10, -36, -101, + -99, 75, 46, 96, 44, 2, -15, 56, -17, -75, -19, 48, 46, -64, 51, -35, + 23, -67, 60, 9, 64, 9, 22, -97, 43, -78, -67, -41, 33, -21, -39, 40, + 96, 15, 15, 15, -61, 4, 31, -71, 44, 45, -24, 113, 32, -58, -45, 55, + -127, -77, 89, 41, 18, -59, -47, 62, 2, 32, -69, -31, -47, 54, 0, 29, + 10, 10, 22, -40, -103, -64, -38, 6, -4, 27, -40, -12, -5, -27, 87, 19, + 30, 2, 114, -44, 0, -14, -5, -62, 76, -55, -35, -87, 62, 10, 38, 112, + -40, 14, 8, -29, -39, -13, 95, -33, 61, 18, -31, -51, -35, 36, 9, 28, + 27, -19, -40, -106, 45, 67, -61, 20, 19, -30, -62, -49, -54, -23, -11, -4, + -17, 21, 90, -11, -12, -20, -26, -70, -35, 29, 65, -10, -103, 81, -32, 9, + -17, -15, 47, 69, -34, 13, -76, -62, 0, 17, 45, -127, -65, -1, -11, 5, + 73, -24, -30, 0, -23, -48, -7, -52, 18, 73, -14, 89, 26, 10, 58, -23, + -37, -11, -76, -37, -81, 127, 33, 78, 50, 61, 17, 22, -88, -74, 40, -41, + -3, -81, 43, 49, 100, 52, -18, 34, -66, -22, 0, -44, -76, -67, -7, -38, + -44, 25, 53, 113, -85, -63, 34, 53, -63, -58, 0, -1, 75, 50, 12, 18, + 23, 34, 5, -60, -3, -41, -3, -75, -24, -60, -29, -74, -80, -52, -79, -42, + -127, -25, 79, 37, 35, -14, 44, 20, 25, -53, 25, -21, -27, 34, -15, -47, + -22, 38, -14, -36, 38, -8, -36, -33, 7, 4, -6, 25, 9, -13, 57, -1, + 87, -16, -47, -64, 27, 16, 38, -47, 64, 9, -43, -73, -70, 7, 38, -37, + -40, 80, 42, -26, -70, 54, -98, 50, -34, -6, -20, 14, -79, -9, -3, 34, + -86, 29, -87, 5, 14, -64, 33, -12, -2, -12, 57, -89, 22, 18, 34, -70, + -16, -105, -49, -60, -19, -66, -58, 51, -3, 20, 72, -26, -2, -127, 43, 87, + 27, 62, 10, -24, 33, 49, -3, -66, -9, -20, -31, 30, -6, -41, 31, 95, + -2, 28, -5, 50, 17, 43, 1, 48, -63, -1, -67, -28, 9, -23, -7, -5, + 19, -127, 28, 55, 4, 61, -47, 47, 43, -30, 51, -65, -25, 28, 8, -75, + 0, -5, 45, 5, -90, 79, -18, -15, 33, 37, 18, 20, -17, 9, 52, 50, + -14, -46, 21, -2, -35, 4, 6, -53, 11, -19, -31, 56, -19, 24, -45, 28, + 38, -42, 8, 11, -30, 61, -78, -32, 10, -11, 42, 32, 26, 18, -1, -15, + 60, 46, -117, -43, -15, 47, -21, -102, -72, 15, 27, -53, -24, 21, -26, -117, + 34, 20, 127, 9, 26, -60, -38, 62, -17, -43, -16, 56, 14, -36, -25, -21, + 28, 50, -8, -116, 31, -16, -43, 46, -47, -58, -17, 61, 54, -51, -58, 45, + -30, -110, -46, -48, -64, -46, -10, -4, 1, -31, 41, 45, 18, 41, -47, 65, + -69, 46, -21, -13, -53, 27, -16, -31, 20, -15, 30, 51, 46, -23, 38, -18, + 77, -36, 54, 50, -44, 9, -29, -38, 1, 69, -1, 40, -34, -17, 76, 127, + -68, 69, -3, -25, 32, -36, 1, -61, -11, 31, -64, 56, 26, -53, 48, -5, + 67, 25, 24, -30, -7, -33, 32, -37, -2, 7, -67, -65, -13, -46, -51, -28, + -11, 8, 84, -19, -61, -4, 70, 73, 44, -39, 79, 101, -12, 15, 25, 3, + -90, -24, 23, 33, -19, -77, 97, 80, 54, -33, -4, -75, -33, 73, -20, 127, + 81, -59, 72, 70, 71, 61, -80, -55, 93, -8, -88, 7, 16, 36, -76, -28, + 4, -12, -44, 46, 45, 0, -26, -23, 59, -46, 6, 34, -19, -58, -16, 110, + -2, 2, 78, 14, 51, -14, 21, -127, -100, -92, 79, 7, -25, -4, 30, 7, + 40, 65, -67, 12, -54, 64, 11, -23, -53, 81, -14, -38, 13, -15, -45, 22, + -32, 46, -76, -100, 50, 56, -22, -39, 37, -7, -11, 25, 33, 62, -5, -61, + -14, 47, 30, 5, 62, -57, -47, -49, 15, -32, 49, 127, -19, -9, 41, 32, + -60, -49, -4, -46, 60, -39, -15, -19, 39, -93, 111, -36, 70, -70, -38, -5, + -62, -13, -9, 53, -55, -11, -2, -14, 75, 35, -113, -62, -119, -100, 96, 16, + 32, -12, 53, -85, -14, 59, 28, -10, 28, -17, -69, 95, 83, 28, -49, -31, + -76, 8, -16, -18, 70, -13, -56, -16, -89, 65, -87, -35, 63, -30, -35, 28, + 16, -74, 50, -35, 25, -6, 73, -20, -127, -85, -78, -33, 24, 9, -107, -79, + 96, 45, 43, 5, 3, -110, 24, -14, 69, 21, 64, 19, -84, 10, -26, -62, + -20, 31, 84, -92, 64, 22, 28, -25, 45, -67, -65, -39, 17, -11, -103, -87, + 33, 26, 25, 28, 28, 48, -73, -31, 25, -107, 36, 37, 53, -8, -35, 28, + -36, -19, 87, 23, 80, -8, 5, -8, -13, -42, -40, 9, 66, -2, -55, -75, + -43, 36, -19, 48, -95, -123, 65, -5, -1, 2, 68, 19, -19, 14, 21, -87, + 52, 39, -8, -127, 33, -75, -58, -58, -16, -80, -59, 35, 24, -54, 48, 4, + -21, -1, -38, 25, -48, 42, 34, 37, -23, -25, 57, 48, -46, -65, -86, 62, + -30, 26, 11, 14, -3, -1, 21, 10, -57, 27, 65, -8, -71, -30, 46, 24, + 6, -19, -19, 0, 53, 30, 25, 78, 4, -27, -16, 25, 33, -10, 27, 16, + 8, 48, -127, -42, 32, 4, -46, -40, 37, 48, -56, 31, -86, 18, -4, 53, + -109, -79, -112, -78, 35, 75, -20, 107, -19, -20, -4, 80, 12, -37, 25, 102, + 85, -18, -127, 11, -8, -83, 14, 124, -3, 37, -7, -24, 13, 38, -58, -55, + -17, 28, -19, -75, 73, 99, -63, 97, -11, 24, -64, 123, -65, 54, 30, -58, + 87, -91, -20, 31, -64, 25, 62, 63, -99, 24, -26, -42, -67, -82, 68, 97, + -48, -20, -3, 33, 17, 38, -50, -117, 10, -89, 8, -38, 29, -89, 7, 36, + 7, 5, -27, -69, -32, -45, -31, 10, 51, -51, 11, -63, 51, -87, 30, 10, + -19, 48, -83, 21, 63, -48, 39, -30, 25, 1, -34, -35, -16, -14, 76, 61, + -31, 3, -35, 1, 37, -127, -45, -35, -12, -23, -53, 48, 8, 28, -24, 39, + 60, 3, -13, -8, -8, 33, -59, 4, -17, -96, -6, 25, 14, -29, 62, 25, + -34, 3, -47, 3, -58, -83, -111, 23, -64, 10, 57, -127, -24, -13, 123, 4, + 19, -47, 56, 28, 11, -40, -21, 32, -10, 82, -74, -4, -70, 61, 25, -89, + -51, 11, 93, 27, 2, -3, -28, 60, -38, 5, -71, -25, -9, 53, 98, 7, + -8, -125, -4, 61, 6, -31, 25, 35, 3, 18, 47, 27, 32, 18, -41, 13, + -74, 20, 40, -45, 27, 12, 127, 11, 89, -52, 25, 69, 59, 31, -5, 60, + -27, 39, -8, -13, 0, 8, 15, 0, 28, 109, 66, -26, -41, -1, -20, 48, + -28, 95, 28, 53, -10, -33, 79, -67, -26, 10, -88, -16, -94, -21, 12, -11, + 57, -30, 23, 54, -115, 55, 12, 29, -15, 32, 2, -26, 88, -14, -80, 101, + -1, 91, 9, 76, 40, 41, 14, -70, -46, -94, -40, -61, -17, 38, 38, -102, + 75, -72, 101, -98, -67, -69, 65, -123, -30, -9, -94, 99, -106, 44, -12, 19, + 13, -62, -1, 41, 127, -7, -96, 43, 31, -50, -43, 31, -11, -51, -10, 72, + -5, -25, -3, 31, -24, 60, -87, 27, 8, -126, 2, -44, -37, -38, -58, 59, + 6, 60, -19, 116, 22, 53, -59, -58, -12, 62, -65, -29, -1, -19, 44, -127, + 2, 53, 92, -64, -43, 31, -44, 86, 26, 19, -82, 11, -61, 25, 15, 78, + 70, -21, 18, 16, -39, 33, -16, -8, -19, -121, -65, 64, -14, -59, 33, 6, + -17, -21, -42, -68, -2, 15, -49, -36, -10, -10, 127, 6, 26, 5, 59, 14, + -26, -40, -65, 32, 80, -63, -92, 40, 76, -30, 31, 124, -58, 33, -110, 31, + 45, 71, -119, -46, -18, 52, 17, 13, -76, 61, 51, -32, 47, -35, -57, 7, + 29, 70, -9, -71, 23, -29, -74, -19, 93, -18, -47, -31, -116, -34, -62, -50 +}; + +const int32_t Pw1Bias[64] = +{ + 168, -606, 590, 637, -1706, -929, 2368, 3990, + 2180, -900, 3256, -1016, 786, 929, 1329, 1740, + -2497, 1653, 167, -1344, -209, -2914, -1362, 1379, + 2385, -1937, -764, -1363, 1402, 3147, -1557, 2636, + 1064, -1035, 3186, 1976, -303, 1539, 509, -1536, + 929, 1324, 2418, -1038, 2297, -1089, 4360, 2800, + -689, 1943, 161, -2306, 609, -593, 3880, 2625, + -99, -852, 3146, 944, -1975, 1100, 1384, 2719 +}; + +const int32_t Pw1Multipliers[64] = +{ + 2077998708, 1951821704, 1590128657, 1513504250, 2084922191, 1138946778, 1787198879, 1390453559, + 1694564990, 1571478597, 1658130843, 1738756281, 2064540547, 1144388684, 1366207715, 1999844259, + 1879798850, 1450632017, 2096874766, 1561193520, 1593742492, 1727779105, 1732382264, 1908872335, + 1410584213, 1946781365, 2095297596, 1806018348, 1238905180, 1652136525, 1930939329, 1724196153, + 1887170045, 1461699521, 1912360675, 1829289239, 2037914844, 1377135620, 1988793357, 1590655272, + 1848788132, 2046069537, 1586854355, 1700877420, 1735935404, 1601903075, 1997808844, 2053333981, + 1463315697, 1457199543, 1171633830, 2101785683, 1823635526, 1437847121, 1508111524, 1723985506, + 1389949526, 1532659147, 1467452934, 1454309761, 1154408847, 1768040234, 1502797166, 1762030921 +}; + +const int32_t Pw1Shifts[64] = +{ + -9, -9, -9, -8, -9, -8, -9, -9, + -9, -9, -9, -9, -9, -8, -8, -9, + -9, -9, -10, -9, -9, -9, -9, -9, + -8, -9, -9, -9, -8, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, + -8, -8, -8, -9, -9, -9, -9, -9, + -8, -9, -9, -9, -8, -9, -9, -9 +}; + +const int8_t Pw2Weights[4096] = +{ + 25, 37, 10, -19, -25, -51, 48, -24, -49, -32, 106, -49, 25, -66, -16, -26, + 42, 52, -127, 63, 106, -5, -58, 81, 5, -45, -97, -45, 28, 20, -55, 33, + 30, 39, -11, 15, 53, 71, -38, -50, -14, -18, -18, -35, -75, -23, 9, -37, + -23, -12, -41, 10, -65, -14, -62, 78, -18, 30, -16, -39, -34, 29, -13, -42, + -69, -18, 88, 37, -12, -32, 39, -97, 116, -4, 92, -42, -11, -127, 35, -79, + -27, 45, 65, -54, 73, -32, 15, 82, -36, -16, -78, -40, -8, -16, 48, 15, + -17, -28, 1, -25, -9, -16, -50, 23, 21, -34, 42, 62, -39, -2, -47, -69, + -26, -110, 7, -12, 12, -53, -17, -51, 16, -47, -109, -12, 41, 16, 9, -62, + 33, 3, 14, -24, -2, 41, -46, -14, 23, 40, -98, -24, 7, -17, 100, -57, + 5, -31, 91, -52, 21, 66, -118, -44, -2, -17, 34, 42, -77, -55, -16, -41, + -62, -2, -24, 33, -79, -69, -103, 12, 30, 40, 93, 31, -33, 127, -75, 68, + -38, 45, -85, 8, 17, 60, 25, -89, 32, -47, 28, -26, -18, -69, 38, 28, + -45, 35, -6, -39, -15, 32, 59, 9, 127, 31, -16, 51, -7, 1, 25, 59, + 0, 16, -8, -43, 3, -65, 24, 7, -25, -15, -37, 13, -55, -22, 44, 1, + -32, 13, 61, -47, 33, 5, 1, -53, 14, 18, -47, -56, -25, -15, 36, -14, + 77, -67, 29, 26, 18, -82, -50, -22, -89, 43, 59, -6, 69, 4, 4, 90, + 45, 52, -25, -43, 80, -44, 20, 32, -127, -31, 49, 49, 102, 56, -63, 83, + 95, 91, -114, 112, 99, -66, -8, -60, -54, -41, -28, 29, 81, 43, -18, 18, + 26, 31, -57, 105, 56, 33, 34, -8, -25, 15, 43, -89, -28, 58, -23, -119, + -95, -22, 8, 102, -71, -81, 10, -106, 26, 90, -1, 32, 123, -31, 11, 60, + 62, -74, 49, -20, -125, -44, 45, -25, 51, -82, 65, -78, 77, 31, -5, -59, + 76, -50, 63, 3, -4, -40, -85, -13, 53, 15, 27, 0, -60, -68, 32, 7, + 57, 71, 45, -127, 123, 21, 68, -6, -27, -51, 39, 16, -60, -4, 102, 34, + -48, 1, 32, 47, -25, -62, -20, -5, 15, 42, -30, 49, 13, 18, 24, -25, + 91, -40, 28, -115, 27, -9, 95, 90, -35, -7, -32, 16, 101, 26, -27, 8, + -50, -127, -24, 45, -33, -57, -43, 30, 24, 22, 39, -46, -35, 6, -34, 14, + -27, -69, -64, -49, 96, -61, 86, -27, -46, -60, 26, -74, -58, -8, 26, 51, + 100, 35, 1, -78, -45, -18, 68, -46, -14, 66, -49, 39, 60, -46, 54, -2, + 50, -95, 40, 127, -75, -80, -84, -21, 36, 36, 3, 9, -72, 16, 22, -59, + 12, 46, -20, -87, -71, 24, -59, 15, -51, -41, 40, -3, -33, 12, 21, -99, + 20, 47, -35, 12, -30, 47, -36, -58, 28, 4, 24, -86, -68, 30, 39, 0, + 22, 35, -14, 28, 57, -6, -45, -55, 120, -55, -18, 24, -65, 100, -34, 24, + -32, -48, -44, -46, 98, -69, 76, 79, 19, 0, -47, 114, 9, 67, 24, -127, + 52, 21, 46, -123, -80, -12, 84, -87, 22, 105, -38, -34, -97, -40, 90, -37, + -93, -99, -17, -80, 3, -9, 4, 91, -89, 20, -56, -89, -22, 92, 42, 4, + 1, -82, 35, -6, 50, 70, 15, -61, 0, -5, 5, 83, 35, 9, -28, -53, + -64, -29, -11, -24, 51, 46, -3, -7, 53, 80, -89, -11, -40, -30, 41, 10, + -49, -27, 62, -71, -26, 7, 2, -13, 91, 99, 71, 26, -52, -41, 38, 43, + -55, -4, 23, -9, 10, -48, -67, 127, -20, 7, -21, -37, -24, 79, -123, 36, + -55, 40, -22, 16, 84, 111, 55, -71, -13, 46, -27, 40, 1, -24, -1, -25, + 77, -126, -14, -12, 95, 33, -43, -44, 78, -31, 89, -28, 62, -43, 98, -80, + -60, -31, -67, 2, -51, -9, 25, 45, -127, -5, -34, -52, -43, 29, -17, -25, + -23, -15, -47, 56, -72, -12, -13, -80, 20, -49, 48, -86, -78, -25, -14, -60, + 66, -22, -68, -11, 20, 43, 37, 39, 46, -45, -39, -54, -6, 2, -107, -68, + 14, -69, -14, -3, -44, -7, -2, 11, 57, 41, 48, 72, 11, 0, 11, -44, + 46, 28, -55, -89, 10, 4, 35, 10, 13, 7, 7, -61, -58, -16, 58, -3, + -27, -28, -22, -26, 21, 29, -28, 58, -42, 28, -16, 22, 12, -7, 41, 1, + 127, -54, -49, -36, 49, 32, 8, -22, 48, 14, 10, 39, 58, 2, -75, -43, + 37, -81, -17, -10, -14, -7, -26, 25, 80, -14, 104, -51, 68, -71, 85, -89, + 17, 35, -91, -31, -58, -5, 47, -12, -86, -22, -42, -33, -30, 18, 8, -72, + 30, -11, -75, 8, -40, 32, -23, -47, -50, 30, 16, 11, 6, -31, 21, -25, + 51, 25, -25, 14, 103, -17, -104, 54, 123, -77, -15, 6, -35, 127, -62, -17, + -25, -32, 76, -35, -56, -10, 27, -64, 127, 75, -17, 25, -49, 12, 14, 15, + 92, 0, -63, -19, -77, -95, 40, 44, 125, -81, 2, -119, -55, -18, -73, 23, + 28, -86, 33, -91, 50, 89, 70, -66, -86, 32, -14, -63, -78, -98, 110, 98, + 92, -76, 42, 49, 1, -81, 34, -18, 7, -15, 33, 20, 91, -21, -1, -82, + -52, -55, 26, -12, -35, -13, 2, -20, -20, -43, -17, -10, -35, -71, 38, 72, + -56, -7, 52, -58, -60, -23, -31, -16, 31, -4, 60, 8, -40, -17, -22, 23, + -51, -9, 34, -51, -25, 10, 43, -7, 30, -40, 51, -7, -19, 9, -5, 16, + -48, 85, 53, -33, 16, 6, 127, -74, -15, -17, 28, 9, -14, 51, 38, -50, + -9, -72, 16, -64, -83, 51, -13, -48, -57, -15, 24, 28, -1, -43, -68, -44, + 0, -42, 6, -23, 44, -13, 16, 47, 127, 38, -4, -46, -18, -21, 65, 13, + -27, 17, -58, -56, 9, -13, 18, 0, 25, -36, 62, 0, -56, 7, -21, -17, + 31, 30, 6, -92, 24, 50, -21, 8, 12, 32, -29, 107, -9, 36, 5, -35, + -40, 48, -9, 3, 39, 13, 50, -42, 53, 110, 57, 50, -2, 55, -20, -17, + 7, 92, -35, -23, -17, -41, -8, 78, 37, -50, -66, -59, -28, -52, -65, -21, + -10, -18, 47, -1, 49, 127, 48, -69, 62, 16, 8, -39, -26, 4, 9, -6, + -18, -41, 22, -25, 11, -54, -16, 1, 19, 81, -40, -82, 10, -14, 8, -36, + -25, 70, -25, -4, 87, -31, 58, 2, -31, 32, 23, -21, -2, -6, -65, -63, + 34, 15, -28, 30, -12, 9, 42, 1, -53, 20, -71, 6, 18, 53, -31, -33, + -59, -83, -14, 6, -31, 31, -29, -26, -20, 36, 7, -71, -53, 40, -27, -17, + -29, -56, 25, -18, 18, -6, -70, -73, 25, 28, 16, -4, 127, -49, 24, 41, + 70, -48, -111, 113, -2, -127, 26, -12, 43, -41, 7, -29, -22, 30, 68, -13, + -76, 30, -33, -6, 18, 52, 37, 90, -50, -19, 29, -48, -2, 61, -111, -111, + 3, 88, 28, 77, -48, 120, -34, 0, -46, 48, -45, -52, -9, 42, -97, 16, + 71, -35, -61, -45, -9, -42, 11, -9, 95, -15, 61, -4, -48, 38, -4, 55, + 27, -50, 60, 25, -2, 14, -38, -37, 15, 101, -6, -15, -37, 28, 60, 25, + 22, 53, 111, 28, 16, 33, -92, 85, -23, -82, -15, -23, -36, -3, -86, 8, + -38, -57, 65, -1, -58, 37, -79, -11, 75, 18, 64, -51, -20, 43, -40, 68, + -22, 30, -127, 24, -11, 2, 2, 5, 86, -16, 55, -73, -22, -1, -12, 32, + 0, -61, -33, 63, 89, -13, 89, -27, 80, 18, -12, -38, 52, -83, -35, -64, + 15, 100, -24, -27, -29, 22, 46, -25, -77, 27, -81, -38, 25, 58, -98, -51, + -7, -14, -41, 44, -14, 88, -3, 77, -105, 36, -37, -118, -32, -16, -81, -15, + -31, -78, -74, 95, -1, 9, 100, -39, -23, -45, 127, -78, 80, -85, -63, -1, + 48, -6, 35, -90, 43, -53, 21, 34, 120, 58, -112, 50, 104, 72, 100, -78, + 63, -65, -8, -96, -65, 92, -13, -69, -13, 63, -63, -41, -76, 24, -8, -53, + 87, -6, 79, -116, -5, -35, -9, 0, -56, 54, -23, 34, 10, -16, 14, 77, + 64, -127, -2, 29, 83, 46, 59, -86, 97, -89, 5, -16, -17, 82, -58, -25, + -7, 73, -45, -42, 94, -32, 34, 23, 87, 66, 120, -46, 32, -51, -31, 122, + -100, 17, -32, 106, 112, 39, 96, 87, 33, 15, -81, -24, -37, -87, -39, -56, + -91, -5, -54, 55, -13, 41, 12, -16, 99, 18, 11, -38, -55, 61, -11, -115, + 22, -58, 55, -77, 6, -96, 30, -32, -51, 108, -127, -86, 80, 9, 62, -36, + -4, 22, 7, 87, 28, -44, -25, -14, 18, 34, 106, -76, -28, -63, 32, -43, + 0, 127, -32, 1, 103, -20, -42, 40, 28, -83, -40, -5, 61, -16, -48, -42, + 5, 63, -37, 62, -25, 101, -50, 23, 30, -30, 74, -62, -98, 79, -48, 45, + -26, -21, -86, 76, -72, -50, 4, -33, 33, 17, 11, -13, -11, 13, 44, 10, + 46, -14, 90, 26, -23, -23, -93, 25, 33, 41, 29, 32, 48, -20, -7, 18, + 9, 5, 127, 9, -73, -8, -39, -35, -3, -8, 34, 49, -93, 76, 23, -29, + 80, 94, 10, 3, -6, -19, -62, -69, 30, -22, -19, 84, -44, -1, 16, -29, + 2, 99, 7, -14, -32, -32, 34, -32, 28, 45, -3, 33, -100, 47, -32, -26, + 1, -79, 29, -1, 70, -34, 81, 1, -70, -29, -99, 63, -38, 103, -127, -41, + 12, -7, -10, 37, -17, 35, 21, 27, 39, 23, -26, 45, -39, 19, 83, -7, + -30, 10, 10, -15, -18, -22, -28, 38, -63, 74, 15, -12, 15, 78, -14, 43, + 42, -57, -1, 4, 81, 88, 23, -62, 106, -50, 71, 23, -48, -65, 30, -46, + -18, -30, -3, 11, -13, -3, 83, -10, -77, 67, 13, -7, 127, 20, 18, 28, + 69, 26, -15, 38, 40, -77, 8, 2, 11, -37, -78, -98, -29, 76, -41, 37, + 18, 12, -61, -7, 68, 79, 36, -41, -29, -21, 43, -28, -100, -39, 39, 17, + 15, 1, -46, -49, 6, 28, -63, -30, 65, -12, 100, -34, -48, -24, -14, -43, + 17, -44, 64, -37, 0, 67, 8, -15, 4, -1, -92, 127, -15, -27, -8, 79, + 1, -22, 21, 56, -16, -60, 23, 51, 6, 1, 7, 8, -8, -30, 54, 33, + 32, 14, -30, 13, 89, 49, 41, -7, 37, 51, 14, 35, -30, 25, 72, 53, + 65, -41, -75, -24, -92, 9, -28, -59, 14, 81, 25, 0, -12, -14, -17, -11, + -5, -59, 45, -44, 127, 6, 44, 25, 6, 55, 35, -59, 19, -90, 30, -68, + 14, -30, -39, 80, 16, -4, 31, -69, -42, 8, -31, -11, -26, 32, -73, -85, + 54, -61, -53, -82, -29, -23, -58, -40, -91, -31, -44, -70, -80, 49, 19, -62, + 5, -18, -42, 31, -10, -7, 25, -7, -49, -35, -18, -20, 11, 53, -59, -11, + 77, 14, -25, 97, -32, -92, -54, 70, 68, 120, 21, -73, -16, -31, 118, -62, + -11, 114, -86, 56, 9, 39, 97, 24, -61, 18, 52, 29, -10, -2, 21, -57, + -120, -7, 2, 91, -61, -39, -87, -20, -60, 43, -15, 3, -42, 8, -35, 22, + 47, 103, 12, 61, -16, -76, -51, -69, 6, -33, 33, 32, 18, 127, -41, -4, + -2, 19, 32, -83, -15, 43, 23, 2, 72, -47, 15, 69, 117, 76, 14, 67, + -1, 8, -29, -80, -63, -48, 3, 19, 76, -10, 42, 25, 25, -70, 100, -38, + 50, -78, -20, -68, 42, -72, 27, -21, 41, -28, 1, -29, -42, 51, 75, -109, + 70, -33, -101, 2, 61, 9, 30, -127, -20, -1, -93, -32, -32, 39, 64, -44, + -26, 71, -31, -55, -30, 53, -68, 67, 35, 16, -73, 46, -24, 26, -40, 60, + -55, 52, 82, 40, 36, 35, 25, -20, 28, -46, 71, 2, -18, 1, -106, 74, + -53, -8, 38, 50, 72, 45, 28, 38, 91, -13, 7, -127, -57, 62, 17, 30, + -103, 125, 50, 17, -82, -81, 0, -60, -29, 55, 126, 61, -27, 40, -18, 34, + 44, -127, 95, -20, -72, -24, -52, 28, -38, -29, 11, -20, 59, -10, -2, -25, + -3, 0, -29, 78, -6, 0, 6, -76, 1, -18, -34, -55, -38, 78, -3, 40, + 89, -35, 0, -84, 66, 35, -30, 23, -2, -4, -6, 52, -68, -71, 6, 36, + -12, -25, 0, 13, 75, -6, -38, 71, 110, -30, 21, 24, 13, 55, -71, -37, + 11, 33, -79, -15, -20, -61, 109, -19, 9, -23, 33, -29, -34, -15, 9, -4, + -66, 22, -14, 53, 23, -112, 127, 52, 30, 54, -44, -25, 0, 9, -10, -55, + -84, 18, -98, -2, -48, 42, 27, 26, 7, 0, -93, -22, -8, 53, -51, -60, + 69, -23, -21, -20, -2, 88, 50, -21, 26, -13, -66, 82, 37, -60, -39, -6, + -76, -1, 59, 14, 32, 16, 62, 8, 68, 19, 18, -29, -15, -12, 96, -46, + 58, 67, 86, 46, 47, 44, -22, 30, -24, -64, 50, -127, -106, -94, -108, -44, + -41, 75, -6, 6, 59, 72, -19, -42, 64, -22, 76, -23, -46, 117, -97, 17, + 25, -73, -75, 41, 10, 28, 58, -95, 49, -41, 48, -40, -97, -48, 5, 19, + 69, 9, 43, -65, -44, -3, 72, 90, 5, 79, -26, 96, 26, -16, -122, 21, + 77, -41, -12, 48, -127, -29, -21, 16, -6, 53, 57, -37, -112, 44, 14, -18, + 15, -42, -21, -62, 38, -40, 34, 90, -82, 58, 44, -102, -34, -32, 102, 64, + 29, -14, 116, -36, 21, -40, -45, -80, -2, 82, 40, -25, 27, 85, 7, 43, + 10, 7, -65, -28, -16, 29, 127, -31, -75, 44, 22, 55, -15, -18, -72, -99, + 12, 44, 16, 63, -27, -71, 37, 9, -86, 67, -59, -35, 20, -19, 35, -43, + -79, -107, -87, 44, 54, 57, -25, 64, -43, -10, 20, -9, 4, -50, -73, -71, + 59, -31, -23, -21, 9, 36, -22, 7, 14, 63, 4, -16, 38, -72, -7, 0, + 60, 52, -26, -41, -5, 8, 67, 59, -55, 4, -14, -13, -6, 19, -8, 26, + -123, -56, 55, 21, 15, -59, 3, 41, -2, 70, 31, -40, -34, 24, 96, 5, + -36, -53, -55, -24, -32, 39, -41, 14, -11, 1, 3, -40, -31, 25, -35, -50, + 56, 74, -59, -63, -3, -15, 127, -21, -30, 54, -47, 64, -10, 15, 48, 0, + 1, -46, -1, -70, 74, -25, -24, -19, -15, -78, 43, -52, 62, -90, 75, 76, + -83, -44, 41, -17, 75, 11, -46, 46, 19, -51, 22, 19, -1, -47, -32, -32, + 53, 57, -35, -2, 15, -41, -2, 5, 71, -107, 32, -12, -54, 36, -36, -37, + -26, -30, -20, 4, -30, 17, 104, -30, -86, 60, -127, -42, -25, 42, 68, -67, + 56, -2, -14, -43, 44, 2, 26, -59, -33, -77, -84, -12, -4, 6, 28, 73, + 1, -80, 94, 21, 61, -18, 23, 7, 15, 48, 47, 49, 59, -24, 12, -24, + 76, 32, 25, 1, -57, -40, -19, 34, -5, -40, -28, 0, -12, 6, -58, -10, + 28, -16, -63, 1, -4, 127, 96, -47, -74, -34, -19, 52, -13, -19, -20, -12, + -52, -1, -75, -25, -13, -27, -57, 7, -41, 33, 66, -127, -61, 6, -6, 56, + -80, 49, -13, 12, 105, -87, -2, -25, 17, 49, 23, 94, 43, -32, 54, -40, + -20, 47, -14, 110, 8, 24, 51, -24, -8, -21, -9, 5, -52, 122, 72, 1, + -5, -28, 89, -9, 13, 49, -14, -45, 16, 61, -14, -81, 0, 87, -17, -28, + 33, -101, -14, 51, -9, -52, 0, 66, -11, 67, 4, 9, 25, 41, -102, 15, + 49, 59, -96, -55, -71, -8, 8, -6, -30, 7, -28, -39, -68, 69, 3, 37, + 7, -28, -86, 44, -12, 30, 50, 18, 20, 25, 5, -9, -59, 25, 76, 47, + -1, 25, 55, -52, 11, 12, -103, -127, 87, 28, 3, -17, 83, 50, -20, -12, + -88, 57, 66, 33, 40, -17, -60, -67, -23, 67, 5, -8, -35, -76, 64, -11, + 52, 27, 14, 81, 13, 82, -22, 81, 97, -49, -66, 5, -48, 9, -70, 19, + 41, -39, 67, 21, -53, -13, -41, 24, 27, -11, 28, -40, -5, 28, -73, 127, + -4, -3, 33, 68, 68, 3, -21, 37, 48, 28, -15, -43, 2, -29, 13, -1, + -79, 7, -14, 22, 28, -122, 84, -30, -1, -87, 28, 20, -77, -82, -127, 18, + -27, 77, -25, -12, 32, 37, 46, -40, 78, 73, -115, 19, 26, 3, 2, -127, + -80, 123, 9, -27, -39, -76, -36, 33, -20, 93, -79, 78, -69, 40, -17, -12, + 57, -3, -32, -42, 68, 72, -46, 31, 79, -77, -77, 14, -21, -25, -107, 31, + -31, 86, 78, -13, -11, -17, -6, -42, 74, -29, -52, 23, 70, 39, 38, -24, + -102, -72, -88, -81, 16, 53, 2, 37, -47, -63, -58, 24, 115, -40, -22, 82, + 27, 127, 2, -32, 79, -37, -16, -124, 21, -43, 80, 44, -70, -53, 34, -59, + 38, -63, 7, 10, -70, -2, -34, 34, -87, -102, -60, -18, 23, -34, 12, 8, + 21, 22, 47, 26, -39, 6, -30, -26, 32, -24, -48, -53, 5, 9, 1, 53, + 94, -32, 5, 98, 14, -40, -69, -40, 12, -56, 53, 31, -4, 127, -17, -1, + 51, 21, -23, -13, 27, 54, 37, -16, -16, 11, -17, 73, -74, 38, 48, 52, + 109, -1, 91, -63, -46, 36, 11, -27, 59, 59, 94, 8, -44, 2, 52, -15, + -3, -101, -8, 63, -17, -57, -15, 33, 31, 14, 3, 58, -59, 56, -24, 3, + 80, 17, -48, 25, 46, -16, -26, -7, 96, 23, 41, -39, 36, -3, -19, -29, + 52, 2, 13, 10, -59, 2, 54, 72, -102, 76, -74, 81, 33, -8, 45, 29, + 48, -35, 12, 40, -67, 63, 33, 26, 75, -37, 60, 48, -127, 58, -63, -81, + 56, 37, 58, 28, -53, 13, 17, -69, -24, 94, -32, 22, -13, -44, -48, 6, + -6, -54, 33, -5, 12, 45, 6, 40, 71, 11, -36, -76, -20, 70, -32, 73, + -4, 7, -13, -48, -32, 105, -49, -42, 10, -27, -32, -57, -4, -17, 20, 68, + 127, -4, -61, 39, -1, -9, 115, 44, 27, -1, 64, -29, 26, -26, -7, -26, + 43, -32, 96, -11, -71, 76, -11, 43, 42, -1, 7, -45, 63, 55, 63, 29, + 44, -21, -127, -28, 22, -113, 16, 36, 0, -32, 38, -7, -33, 33, -42, -25, + 60, 76, -18, -55, 96, 53, 13, -5, -1, -56, -5, -27, -30, -101, 86, 29, + 67, -50, -84, 12, -25, -70, 33, 14, 93, 125, -53, -18, -52, 7, 24, -74, + -26, -56, -7, 48, -54, 41, -22, 33, -97, -53, -2, 18, 105, -75, -6, 62, + -69, 3, 17, 46, -15, 6, -25, -17, 71, -79, 41, -39, -41, 109, 4, -16, + 77, -7, 73, -82, 33, 69, 73, 10, 34, -100, 14, 51, -81, 1, 19, 51, + -5, 118, -19, -86, -46, 56, 87, -29, 90, 127, -45, 82, -97, 9, 11, -44, + -46, 36, 20, 48, 57, -37, 41, 39, -35, -33, 8, -10, 42, 58, -117, -19, + 17, 93, -82, -27, -43, 14, -110, -60, -15, -6, -44, 1, 40, 84, -40, -10, + 28, 38, 34, 125, -69, 42, -61, 28, -34, 39, 3, -127, -54, 87, 11, 1, + -53, 25, 113, -40, -11, 9, -41, -10, -100, 4, -51, -72, 125, 58, 46, 24, + -45, 16, -26, 55, -43, -6, 34, -27, -39, 109, -29, -43, 51, -35, 37, -73, + -21, -9, -11, 75, 11, 34, 31, -11, -79, -26, -12, -100, -23, 112, -33, 9, + -23, -81, 12, 77, -75, -20, -72, 16, -82, 13, 55, -95, -73, 56, -127, 9, + 12, 9, -27, -6, 55, 14, -11, -52, 106, -112, 78, -45, -12, 6, 10, 19, + 11, -127, -10, 37, -2, 60, -52, 3, -36, 58, 46, 13, -17, -37, 70, -41, + 11, -19, 4, -83, 28, 80, 35, -24, 34, 27, -7, -2, -24, -65, 52, -14, + -36, -39, 30, -10, -15, -23, -14, -25, 53, -8, 8, 48, -45, 43, -41, -14, + -40, 51, 30, -48, 30, 28, 25, 20, 21, 44, -83, 36, 23, 93, 3, -99, + -106, 4, -20, 15, 4, -59, 16, -26, -33, -56, -3, -5, -40, 41, 13, 5, + 19, -16, -37, 98, 22, -5, -41, 37, -25, 48, -20, -28, -45, 126, -24, 47, + 66, -28, 23, -20, -49, 14, 17, 71, -81, 51, 12, 19, -39, -7, 22, 30, + 17, 2, -28, -45, 60, 40, 2, -2, 91, -46, 29, -86, -127, -21, 19, -43, + -126, 41, -40, -29, 32, -112, 70, -33, 74, -127, 53, -72, -62, 2, -26, 91, + -80, 13, 68, -29, 8, -16, -67, -50, 12, 60, 82, -22, -18, -30, -55, 5, + 21, -14, 21, -92, 39, 66, 101, 126, 85, -66, 51, 47, -56, 80, 17, 35, + -3, -59, 52, -59, 28, -25, 111, -78, -68, -6, -113, 30, 99, -14, 126, 3, + -12, -71, -29, -85, 8, 3, 13, 59, -9, -43, -1, -87, 29, 31, 15, -60, + 0, 73, 4, 48, 51, 27, 14, -27, 33, -4, 16, 14, -10, 0, -2, -32, + 5, -3, 21, 26, -44, -24, 18, -8, 2, 12, -20, -6, -4, 8, 3, -9, + 19, -55, 38, 31, -36, -77, -69, 26, -23, -71, -59, 59, 39, 95, -127, -2, + -26, 52, 10, 70, 7, -7, -46, 40, 96, 28, 40, -72, -97, -29, -67, -6, + -22, 50, 76, -14, 45, 2, 31, 3, 52, 5, -75, 96, 55, -77, 48, 17, + 10, 50, -33, 68, 23, 68, 74, -59, 20, 58, 42, -46, -50, 44, -32, 24, + -95, 30, 127, 23, 8, 81, -52, -32, 17, 17, -22, 35, 71, 15, -28, 3, + 40, -76, -27, -21, -106, -37, 12, -20, 19, 38, 40, -9, 22, 55, -31, 65, + 103, -40, -91, -31, 17, -109, -49, -7, 25, 44, -94, -108, -46, 15, 32, 48, + -28, -64, -45, -80, 112, 91, -64, -8, -38, 17, 31, 69, -102, -47, 127, 68, + 83, -29, 9, -57, -74, 24, -42, 24, 25, 46, 78, 55, 35, -61, -25, -51, + -19, -12, 6, -27, 9, -14, -76, 63, -19, -10, 21, -48, 17, -21, 30, 39, + -32, -42, -66, 44, 89, 36, 6, -23, 127, 68, 26, 3, 41, -24, -7, -29, + 22, 76, -52, 41, 72, -6, -10, -3, -60, -30, -18, 40, 23, 6, 52, 25, + 31, 57, 56, 38, 29, 92, -4, 41, 4, 3, -50, 65, 101, 2, -8, -51, + 14, -16, 44, 64, -15, 11, -78, 40, -85, -91, 86, -96, -19, -22, 13, -9, + -45, 108, -52, 16, 2, 25, -74, -71, 17, -30, -26, -42, -83, 61, 101, -28, + 58, 31, -80, 59, -4, -5, -41, 20, -61, 14, -13, 26, -44, 38, -17, -51, + -77, 75, 0, -117, -63, 52, -105, 7, 127, 77, -15, -10, -74, 91, -118, -53, + -90, -47, 33, 9, 38, -47, 48, -51, 28, -62, 100, -61, 27, -62, -6, -77, + 44, 81, 4, 53, 4, 30, -59, 18, 43, -5, 8, -22, 19, -39, -11, -23, + 112, 69, 60, 24, 13, -16, 1, -21, 54, -9, 127, 58, -71, 64, -24, 63, + -104, -82, 67, 0, 24, -78, 54, 55, -68, 4, -101, -65, 83, 2, 55, -78, + 45, -52, -15, -35, 3, 5, -10, 90, 25, 114, -127, 3, 44, -10, -2, 94, + -57, 19, 6, 55, -73, -72, 1, -104, -67, 15, 61, 41, -25, 77, -15, -3, + -57, -36, -41, 38, -17, -38, 30, 43, 41, 51, 20, -51, -65, 30, 30, 47, + -37, 120, 82, 39, 42, -67, 46, -39, -49, 48, 30, -25, 74, 27, 14, 57, + 7, -73, 69, -38, -53, 17, -4, 60, 35, 122, -18, 68, 25, -6, 47, 1, + 38, -24, 58, -23, -52, 6, -23, 35, 37, -42, 44, -41, -127, 67, -29, 82, + 18, 26, 6, -21, 34, -13, -71, -83, 53, -5, 73, -36, -93, -33, 13, 51, + 5, 78, -50, 18, -2, 10, 69, -12, 122, 36, 69, 32, -98, -21, -36, -40, + -17, -32, 83, -90, -27, -13, 27, 24, -6, -50, -104, -10, 54, 76, -94, 85, + 9, -38, 17, -12, -20, -53, -41, -17, 11, -42, 1, -25, -44, 19, -28, 5, + 91, 19, -46, 1, 127, -18, 4, -52, -4, -69, 65, 4, -48, 87, 36, 63, + 9, -34, -91, -18, -56, -9, -8, -124, -1, 50, -69, 20, -61, -42, 84, -93 +}; + +const int32_t Pw2Bias[64] = +{ + 4333, 6041, 1487, -688, -2706, -300, 1819, 3447, + 2463, -955, 7962, -216, 3728, 1855, 1514, 1686, + -43, 2137, -704, -469, 5088, 197, -1814, 336, + -2327, -1664, 1451, -3694, 7287, -1409, 349, -3781, + 1630, 967, -3, -1229, 4135, -611, 3188, -1304, + -2109, 1554, -2900, 2560, 2987, -5779, -2121, -2705, + -166, -2207, 935, 4592, -179, 1435, -1861, 2139, + -4767, 2309, -6379, 4937, -906, -2804, -1503, 4278 +}; + +const int32_t Pw2Multipliers[64] = +{ + 1204655980, 1722574913, 1856033158, 1303315652, 1469056777, 1591146126, 1509369530, 1728050027, + 1601779160, 1548065473, 1246153975, 1153600612, 1094795836, 1820569484, 1419304710, 2075758483, + 2081821059, 1388518863, 1631476569, 2076634147, 1221826522, 1687469465, 1564662189, 1539583026, + 2059988782, 1102360481, 1214621700, 2079186203, 1076850979, 1459760582, 1945164574, 1505867118, + 2124579972, 1941993976, 1510897889, 1541590985, 1885520619, 1764501773, 1142225696, 1966944026, + 1573704703, 1964372683, 1116848994, 1241974667, 1455318501, 1669634312, 1874460810, 1346901582, + 1433740767, 1185701062, 1761827728, 1956644649, 1233833617, 1958606417, 1524407790, 1853935888, + 1626973064, 1083204461, 1731467428, 1589459047, 1653410932, 1707134078, 1492912615, 1834071768 +}; + +const int32_t Pw2Shifts[64] = +{ + -8, -9, -9, -8, -9, -9, -9, -9, + -9, -9, -9, -8, -8, -9, -8, -9, + -9, -8, -9, -9, -9, -9, -9, -9, + -9, -8, -8, -9, -8, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -8, -9, + -9, -9, -8, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -8, -9, -9, -9, + -9, -8, -9, -9, -9, -9, -9, -9 +}; + +const int8_t Pw3Weights[4096] = +{ + 63, 2, -94, 20, 70, 4, 62, 47, -26, -1, 19, -84, -15, 48, -114, -29, + 8, 9, 52, -4, -17, 48, -39, 44, 38, 4, 99, 61, 12, 26, -5, 48, + 85, -15, 53, -57, -13, 31, -55, -98, -18, -15, -61, -99, -18, 51, 47, 30, + 19, -25, -12, 28, 26, 1, -38, -46, -35, 127, -7, 12, 31, 12, 51, 3, + -15, 8, -1, 73, -11, -14, 71, -4, 33, -17, 36, -127, 22, 19, 30, -41, + -15, 81, -5, 9, -3, 9, 26, -30, -17, -29, -51, 54, -10, 10, -6, 52, + -1, 50, 20, 1, 18, 3, 61, 32, -23, -28, -83, -7, 0, -65, -91, 30, + -6, -41, -10, -11, -9, 7, 30, -19, -47, -2, -29, 44, -32, 25, -7, -22, + -80, 4, 93, -1, -95, 83, -97, 50, 16, 108, -57, -27, -64, 14, 99, -51, + 36, 16, -117, -28, 2, -18, -6, 24, 3, 27, -40, 21, -78, -38, -105, -38, + 26, -82, 127, 22, -34, -106, -2, -57, 23, -81, -35, -60, 40, 36, -95, -12, + 52, -48, 21, 18, 49, -6, 61, 6, 9, 57, -81, -97, -14, -2, 61, 35, + -38, 52, -48, 73, 12, -32, 83, 89, 102, -4, 61, 34, 62, 127, 11, -39, + -28, 20, 40, 72, -23, 67, -63, -20, -51, -8, 17, -71, -6, 13, -65, -101, + 20, 20, 13, 8, 8, 36, -4, -69, -109, 87, 19, -59, -23, 13, 1, 35, + 111, 7, -25, 64, 120, -64, 17, -16, 91, 66, -44, -74, 37, -32, -15, -30, + 69, 11, -11, -57, -31, -12, -127, -98, -55, 29, 17, -9, 19, -90, -59, 37, + 7, 32, -10, 60, 25, 42, 14, 77, 37, -42, 44, 76, 103, 48, 36, -17, + -23, -24, 19, 43, -22, -21, -13, -14, 109, -56, 101, 36, 37, -41, -22, 50, + -33, 35, 72, -21, -97, -45, -27, 2, 20, -64, 8, -39, 25, -83, 38, 27, + -11, -7, -31, -43, -43, -64, -12, -65, 1, -15, 123, -24, 52, -16, -27, -38, + 10, -13, -37, 56, -4, 37, 49, 40, -64, -70, -22, 48, 90, 6, -86, 34, + 36, 36, 14, 70, 98, -54, 41, -26, -6, -34, 39, -72, 6, 14, -21, -5, + -72, -4, -98, -43, 1, -127, 88, 40, 33, 9, 35, 25, -50, -61, 55, 8, + 21, -46, -90, 56, 5, 7, -55, 24, 59, 33, -29, -3, 14, 48, -88, -15, + -18, -56, -92, 52, 46, -3, -53, 5, 64, 28, 71, 4, 47, -4, -127, 3, + 40, -33, -37, 21, -21, -56, -30, -67, -9, 39, 46, -71, 9, 61, 92, -14, + -37, -16, -12, -13, 36, 50, -34, -24, 19, 127, -3, 7, 58, -108, 27, -12, + -4, -49, 86, 57, -33, -31, -45, 110, 3, 57, 15, 41, 60, -70, 4, -22, + 15, -43, 16, 3, -33, 21, -11, 49, 83, 9, -1, -23, 52, 42, 84, -31, + 4, -50, 29, 27, 3, -69, 16, -25, 11, -7, 25, 70, 17, -23, 9, -36, + 56, 26, -26, 23, -59, -60, -127, 96, -16, -37, -17, -75, 1, -15, 62, -25, + -64, -10, 15, 7, 39, -64, -35, 20, 84, 35, 16, 24, 87, -11, 4, -37, + 8, -10, -33, -16, -27, -30, 10, -39, -7, 37, -58, -127, 112, 42, 15, 50, + -17, 3, -76, 2, -29, 15, 38, -9, -42, 20, 67, 17, 12, -60, 52, 21, + -67, 5, 55, -16, 15, 23, 21, 110, 28, 4, -83, 6, -12, -11, -33, -28, + -67, 24, 38, -11, 83, 11, -127, 15, 31, -22, -43, 36, 0, -106, 78, 88, + -37, -100, -11, -73, -22, -38, 14, -58, -21, 86, -2, -24, -58, -65, -21, -1, + -47, 16, -24, -29, -11, -65, 4, 63, 1, -75, 26, 56, 87, -49, 49, -22, + -57, 65, 9, -69, 6, 30, 77, 35, -28, -55, -1, 74, 21, -44, -13, -29, + 2, -88, 48, 46, 34, -6, -80, -43, -22, 7, 34, -68, -35, -57, -5, -58, + -32, 20, -2, 16, -35, 26, 49, 2, -41, -56, -46, -90, 85, 69, 50, 58, + 11, 32, -17, 64, -31, 7, 56, -20, -44, -107, 48, 36, 51, -105, -70, -59, + -34, 16, -3, 32, -55, 24, 66, 127, -18, -76, -54, -56, 1, -54, 23, 2, + 24, 22, -59, -30, -11, 31, 9, 62, 93, -34, 35, -111, -34, 113, -69, 69, + -40, -50, 47, -1, 62, 65, -93, -51, -48, 53, 37, 20, 4, -22, -52, 31, + 55, -26, -47, 18, 21, -8, -61, -88, -95, 7, 73, -51, 25, 55, 86, 19, + 43, -12, -127, -52, 30, 54, -3, -30, -49, 90, -1, -6, 18, -34, -1, -35, + -63, 23, -10, 52, -84, -24, 105, 114, 120, 7, 127, -50, 88, 27, -32, 0, + 28, 6, 10, -42, -47, -14, -12, -19, -7, -76, -8, -4, 46, 64, -20, 108, + 30, 5, -20, 17, 33, 48, -10, 5, -2, 13, -3, -35, 13, 19, 10, 11, + -35, 17, -29, 7, -4, -59, -30, 20, 19, 5, -30, 59, -3, 60, -46, -43, + 8, 41, -57, -28, -14, 21, -39, 2, 37, -28, -14, -38, -28, 88, 42, -21, + 30, -35, -43, -28, 34, 14, -1, 13, -14, 2, 14, 36, -46, -45, -44, 2, + 28, -19, 53, -49, 47, 5, 10, 28, 25, 9, 8, -7, -19, 17, -3, -13, + 77, -8, 7, -16, 127, -11, 27, -41, -42, 62, 28, -26, -37, 10, -26, 22, + -89, 37, -4, 49, 6, 56, -75, 20, 12, -67, -23, 66, -18, -13, 112, -28, + -20, -40, -48, -26, 18, -30, -4, -49, 51, -33, -61, 42, -74, -3, -127, -64, + -52, -47, 11, 33, -19, 3, 47, 28, -16, 23, -40, 2, 99, -18, 43, -59, + -3, 14, 38, 20, 61, 88, 122, -15, -10, -51, -19, 73, 20, -2, 17, 31, + 7, 59, -32, 46, -13, 46, -20, -13, 43, -33, 5, -70, 48, -2, -44, 49, + 40, -9, -70, -29, 54, 2, -16, -3, 85, 46, 8, 110, -96, -54, -82, 127, + 9, 13, 14, -38, 74, -54, 34, 11, 53, 39, -16, -37, -32, 82, 86, 22, + 33, 11, -38, -96, -36, 17, -48, -85, -72, 115, 17, 94, 10, 72, -50, 55, + 62, 30, -47, -34, -107, 49, -68, -16, -33, -88, 41, -85, 12, 116, 56, -79, + 80, 23, -29, 47, 0, -77, 110, 97, 31, -127, -21, 83, -104, -33, -124, -48, + -18, 57, 59, -50, 77, 59, 1, 21, 57, -14, -70, -5, 33, 38, -71, 82, + 46, -47, 43, -15, 94, -43, 74, -96, 22, 54, 57, -74, -3, -36, -71, 61, + 46, -8, 36, 30, -127, 3, 23, -23, 58, 18, -59, -54, 11, 35, -57, -43, + 15, 78, -13, 15, -51, 21, -7, -7, -23, -33, -59, -83, 87, 30, 34, 94, + -56, 14, -63, -15, -81, 63, -12, -50, 123, -18, -69, 125, -34, -49, -17, -56, + 34, 25, 72, 4, -19, 21, -48, 54, -16, 11, 14, -26, 61, 29, -88, -26, + 68, 32, -32, 40, 83, -47, -33, -22, 28, -29, 78, -75, -14, -29, 27, 26, + -15, -78, 74, 113, -61, -33, 8, -9, -89, 113, -25, -102, 35, 59, -1, 122, + 45, 49, -58, -86, 43, 74, 67, -55, -77, -70, -3, 88, 40, -73, -26, 37, + -73, -6, -40, -38, -91, -4, 75, 127, -119, -59, 27, 72, 39, 60, 4, -24, + -1, -19, 127, -29, 38, -8, -95, 52, -62, 35, -4, 74, -49, -72, 66, 47, + 69, -31, 100, 108, 19, 8, 20, 20, 37, -14, 27, 47, -18, 8, 5, -117, + 18, 13, 84, 12, 7, -21, -68, -59, -11, -28, -25, 7, 44, 6, -56, 13, + 25, -17, -45, 85, -10, -43, -27, -2, -55, 20, -28, -54, -38, 35, 11, 8, + 29, -20, 34, 2, 49, -127, 26, -3, 15, -45, -2, -64, 36, -15, -16, -14, + -6, 105, 118, 63, 22, 29, 27, 7, -19, 12, 23, -5, 125, 98, -50, -56, + 0, -4, -34, -7, -51, 9, 21, -29, -54, 10, 11, -45, 55, -4, -33, 24, + -74, 43, 11, 77, -53, 3, -11, 8, 60, -2, -36, -52, 32, -5, -25, -70, + -92, -25, 53, 80, 12, 46, -22, 19, 95, 55, -7, -76, 13, 110, 1, 6, + 9, -49, -83, -36, 24, 97, -89, -4, 2, 59, -3, -75, 127, -25, 9, 108, + 69, -87, -1, 67, -26, 66, 82, -99, -35, -53, -17, 63, -10, -61, 70, 72, + 99, 1, 75, 27, 74, -10, -89, 43, 15, -29, -95, -96, -73, -31, -8, 46, + -46, -1, -60, -34, 42, 26, 36, -98, 66, 14, -17, -78, 15, -12, 51, -35, + 33, 127, -35, 27, -14, -38, 27, 56, 14, -71, 10, -51, 15, 0, -76, -80, + -26, -27, 60, -17, -32, 5, -13, -39, 13, 21, 4, -26, 37, -52, -48, 33, + -19, 33, 51, 65, 49, -23, 80, -56, 80, 24, -58, -63, -2, -79, 34, -16, + -1, -20, 75, 35, 26, 29, -74, -1, -49, -54, 29, 13, -8, -90, 28, -82, + -14, 55, 127, 69, -92, -68, 82, 27, -10, -44, -55, -24, 49, 41, 79, -12, + -8, -38, 46, 16, 34, 0, -11, 10, 61, -89, -15, 49, 12, -69, -59, 20, + 16, 26, -13, 25, -26, -93, -36, 10, -77, -50, 13, -62, -68, -16, 20, 20, + -15, -76, 32, 51, -31, 64, -71, 97, -24, 19, 36, 85, 17, 31, 44, -42, + -18, -70, -75, -45, 95, -2, -41, -20, 70, 12, 16, 76, 37, 44, 31, 17, + 9, -48, -27, 18, 41, -44, -29, -37, -14, -22, -34, -59, 106, 29, 33, 32, + 55, 41, 6, 32, -9, 46, -32, 61, -14, -21, -32, 40, -3, -32, 127, 81, + -59, -41, 30, 35, 7, -35, -47, 9, 127, 30, -16, -53, 13, 11, -21, -9, + 46, 50, -24, -15, -27, -16, -22, -30, 4, 47, -20, -51, 7, -11, -2, 27, + -7, 46, -2, -38, -18, -19, -23, -7, -43, 35, 32, 21, 34, -8, -26, -33, + -26, 12, -10, 34, -25, 35, 8, 15, 11, 25, -67, -2, -24, 1, -25, -17, + 36, 1, -37, 29, 54, -54, 27, 7, -38, -40, 7, -47, 55, -24, -71, -29, + 38, 59, 28, -2, 21, -24, -16, 5, 70, -20, 87, 8, 127, 78, -18, -2, + 26, 35, 2, 45, -6, -3, -14, -85, -35, 15, 10, -39, 46, 43, 30, -23, + 3, -2, -26, 9, -2, 34, -31, -10, 65, -9, -2, -12, -19, -45, 78, -32, + 27, 50, 73, -127, -36, 84, -69, 13, -29, -13, -67, 89, 48, 21, -73, 92, + 6, -74, -94, 69, -29, -20, -41, 77, 74, 63, 35, 53, -110, -83, 21, 5, + -38, 66, 103, 7, 87, -95, 43, 19, 63, -17, 73, -20, 32, -8, 5, -34, + 16, -87, -43, -19, -50, -89, -40, -55, 13, 95, -7, -8, 48, -13, 14, 83, + 59, -13, -35, 124, 68, -26, 76, -54, -105, 6, -2, -2, -16, 1, 27, 67, + 20, 19, 68, 81, -41, 2, 47, -37, -38, 4, 41, 5, 75, -17, 58, 59, + 92, -20, -48, 8, -26, 49, 42, -14, -59, -87, -107, -33, 40, 13, 34, -37, + -12, -64, 32, -16, -58, 127, 96, 56, -80, -16, 50, 21, -26, 74, -19, 68, + -1, -9, 62, 0, -32, -44, 45, 122, 28, -52, 42, 55, 58, 3, -43, 36, + 20, -52, 112, 64, 43, -85, -8, 3, -7, -54, -48, -19, 21, 127, 16, 6, + -61, 38, 23, 22, 20, -30, -27, 36, 31, 39, 22, 5, 50, -12, -29, -16, + -20, 58, -43, -9, -42, -2, -47, 89, 78, -81, -29, 61, 40, -30, -13, -40, + -39, -9, 72, -53, -62, -8, -89, -74, 49, -7, 58, -28, 22, -13, 9, -30, + -12, -36, -44, 56, -50, 38, 58, 45, -25, -54, -58, -20, 51, -1, 6, 60, + -2, 28, 31, 36, 37, -54, 63, 25, 34, -41, 71, 23, -20, -31, -55, 35, + -49, -34, -4, -39, 6, -127, -17, 42, -18, 7, 36, -39, 12, -54, 31, 19, + 2, 7, 127, -28, -53, 29, -74, 36, 26, -44, -58, 71, -17, -85, -4, 4, + -2, -113, -42, -28, 16, -36, 39, 18, 102, 42, -40, -12, -45, -6, -23, -4, + -43, 11, -30, -48, 28, -59, -43, 57, 95, 39, 62, 63, 28, -2, 39, 1, + -41, 4, 38, -62, 11, 18, -57, 40, -32, -40, 11, 76, -14, -34, 37, 23, + -25, 6, 46, 97, -5, 18, 44, 83, -8, 21, -24, -10, 47, -7, -3, 11, + -41, -45, -65, -15, 40, -1, -21, -18, 127, -33, 42, 75, 57, 2, -13, 51, + 24, -77, 30, 32, -16, -7, -41, -2, -3, 11, -75, 5, -3, 68, 73, -25, + -12, 48, 11, -17, 16, 62, -61, -4, -21, 54, -6, 40, -16, -18, 23, 82, + -6, -63, -39, -9, 4, -11, -96, -29, 92, 34, -24, -43, -10, -77, -53, -42, + -39, 67, 113, -13, -29, 3, 92, 21, -77, 37, 47, -81, 11, 25, 55, 55, + -71, 52, -23, -127, -38, 0, 2, -41, -53, 15, 37, 92, 65, -58, -10, 25, + -72, 63, -55, -53, -124, 43, 14, 7, -24, -15, 53, 9, 22, -53, -85, -81, + -2, 2, 20, -6, 20, 3, -13, 55, -15, -66, 41, -67, -35, -25, 58, 28, + -7, -54, 127, 37, -7, 8, -47, -41, -2, 53, -17, 2, -70, 27, 0, -51, + 25, -10, 43, 35, -29, 54, 11, 20, -66, -37, -30, 1, 21, -48, 4, 1, + -16, 8, -7, 28, -4, 40, 27, 18, -82, -20, -41, 0, 41, 39, -66, -5, + -57, 2, -116, -11, -60, 23, -15, 70, 94, -35, 1, -18, 9, 127, -97, -32, + -6, 51, -81, -34, 28, 36, -74, 36, 24, 68, 39, 28, -23, 40, -89, -33, + 12, -34, -76, -39, 9, -10, 5, 1, 17, 90, 65, -73, 67, 105, 50, 37, + 74, -29, 8, -35, 58, 44, -16, -85, 13, 29, -22, 39, 42, 7, 45, -15, + 67, -24, -10, -13, 9, -110, 29, -116, 91, 29, -18, -84, 9, -44, -107, 68, + 33, 117, 17, -5, -2, 50, -9, 88, -123, 17, 16, 16, 7, 25, -116, -19, + 14, 79, 13, -52, 31, -99, -58, -58, -59, 8, 37, -88, 71, 71, -121, 1, + 20, -28, 32, 16, -34, 29, -20, -20, 31, 127, -59, -23, 36, 59, 85, -27, + -50, -11, -27, 22, -37, -36, -52, -42, 49, -9, -22, -25, 10, 23, -31, -25, + 47, 11, 4, 4, 49, -36, -64, -23, -35, 26, -6, -64, -2, -24, -110, 8, + -35, 48, -9, 26, 46, -43, 8, -71, -67, 36, 102, -68, 71, 50, 41, -32, + 42, -18, -31, 33, -1, 58, -9, 8, 37, 127, -39, 22, -26, 16, 41, -44, + 42, -33, -39, 43, 103, -26, -80, -63, -54, -12, 36, 56, 10, 0, 46, 12, + -53, -35, -40, -13, 14, -22, -30, 5, -52, -15, 26, 41, 79, -8, -9, 26, + 45, -25, 76, 57, 27, -32, 77, 0, -25, -30, -37, -61, 53, 18, 20, 9, + 31, -20, -21, 31, -32, 6, 127, 1, 4, -4, -50, -35, -78, -30, 7, 28, + -14, -107, 117, 35, 71, -95, -91, -38, -1, -8, -1, 60, -49, -56, 36, 33, + -72, -33, -5, -9, -17, 58, -42, -63, -72, 28, -10, -65, 65, 26, -37, 44, + 7, -66, -60, 55, -54, -70, 11, 26, -48, -124, 105, 60, 90, -81, 51, -30, + -95, 32, 7, 59, -42, 119, 24, 127, -20, -51, 0, -27, -1, -101, 20, 52, + 27, 22, 48, -25, -27, 39, -73, -23, -12, -34, -48, 14, 21, -87, 20, -9, + -30, -43, 57, 19, -29, -36, 98, 16, 91, -53, -51, 17, 29, 35, 65, -22, + -62, 20, -12, -56, 62, -8, -10, -12, 127, 47, 12, 56, 72, -69, -10, -36, + 31, -25, 45, -21, -29, -14, 1, 12, -43, -92, 32, 71, 10, -36, 33, -15, + -52, -24, -1, -38, -113, -3, 68, 50, 127, 51, 14, 28, -9, 89, -53, -4, + 52, 96, -26, -22, 23, 25, -4, 24, 45, -30, -28, -42, 16, 45, -51, -66, + 20, -48, -74, -12, -68, -5, -68, -11, -14, 107, 35, 12, 55, 69, 30, 51, + -15, 22, -1, 12, 31, -10, -38, -34, 87, 41, -29, -42, -7, 44, -9, 47, + 1, -34, 92, -9, -11, 7, -92, 42, -70, -8, -26, 38, -27, -36, 108, -94, + 42, 33, 72, -10, 27, 4, 16, -14, 49, -10, -2, 84, -69, -46, 2, -61, + 16, -14, 127, -46, 10, -17, 8, -71, 49, -5, -59, 36, 108, 19, -47, 7, + 20, -9, -21, 46, 14, 9, -48, -18, -13, -6, -27, -65, -15, -42, -1, 52, + 18, 57, -31, -59, -24, -35, -22, -37, 97, -40, 72, -32, 0, -17, -22, 23, + -7, 7, 77, 87, -72, -39, 127, 101, -89, -4, 12, -20, -23, -5, -7, -76, + -38, 67, -2, -82, 76, -86, 0, 38, -26, -47, 25, -11, 70, -10, -113, 13, + -54, 40, -29, -9, -4, -107, 102, -45, -67, 12, -10, -16, -9, 8, -66, -62, + 90, 69, -38, -15, -80, 5, -69, -10, -103, -23, 12, 44, -36, 42, -19, -52, + 33, -14, -25, 48, -80, -3, -14, 103, 46, -74, 23, 27, -39, -1, 7, 22, + 59, -39, 89, 85, 11, -7, 114, -23, 43, -67, 41, 49, -34, 64, -14, 92, + 5, -60, 25, -9, 87, -92, 34, 17, -62, 45, 97, -125, -15, -85, -36, 127, + -24, -49, -67, 19, -55, 60, 5, 11, -59, -48, -39, -27, -45, 69, -24, -21, + 5, 51, -74, 18, 118, 51, -19, 23, 31, 106, 81, 22, 10, -44, -121, -53, + 56, 4, -4, 22, -27, 70, -40, -94, 35, -14, 11, -87, 92, 35, 122, -28, + 60, 24, -7, 9, 46, 127, -20, -94, 77, 3, -70, 21, -25, 64, 66, 69, + 2, -1, 15, 27, -82, 84, -58, 124, 85, -14, -15, 67, 58, 3, -50, 28, + 24, -126, 91, 10, 25, -22, -49, 13, 70, 59, -10, -25, -27, 4, -19, 17, + -30, -53, -17, -82, 47, -10, 21, -23, 66, -31, 51, 81, -18, -40, 76, 6, + -19, 22, 39, -52, 58, -51, -127, 26, -18, -37, 98, -6, -54, -22, -7, 26, + -74, 38, -46, 44, 48, -51, 15, -6, 0, -49, 42, 49, -37, 101, 0, 46, + -8, -53, -14, 51, -27, 52, -127, 58, -4, -25, 119, 47, -57, -28, -48, -116, + 60, 26, 120, 50, -5, -43, -8, -56, -76, 88, -35, -114, 112, 33, 63, 38, + 61, 44, -69, 95, 2, 117, -1, -76, 49, 103, -93, -37, 18, -11, -26, -16, + 17, 38, -94, -46, -17, 52, -60, 65, -30, 40, 127, 20, 44, 86, -43, -74, + 35, -20, -77, -44, 38, 40, 20, 77, -62, -71, 35, 59, -55, -15, -45, 76, + 47, 16, 67, -36, 73, -22, 48, -71, -52, -66, -5, -107, 26, 58, 37, 25, + 48, -50, -56, 20, 102, -40, 33, -8, 57, 82, -5, -12, -15, -77, 20, 59, + 59, -8, -52, -13, 20, 26, -25, -12, 19, -2, -58, 61, -52, -22, 28, 26, + -40, -71, -67, -98, 57, 52, -16, 27, 78, -30, -1, 127, -55, -27, -104, 2, + -7, 36, 66, -1, 40, -62, 21, -41, 20, 25, -53, -77, 52, 15, 31, -71, + -31, -32, -17, 31, 10, 46, 66, -39, 19, 80, -42, 101, 36, 14, 30, -2, + -6, -32, -3, 14, -44, -2, 30, -9, -20, -17, 11, -51, 49, 57, -53, -40, + 32, 127, 11, -75, 19, 11, -11, 19, 50, -43, 27, -12, 52, 24, -15, -45, + 2, -37, -2, 13, -59, -1, -51, -17, 51, 36, 1, -14, 23, 33, 26, -5, + -36, -9, 15, 46, 20, -8, -40, -72, 59, 0, 16, -47, -4, -12, 1, 12, + -7, -6, 52, 61, 46, -44, 48, 10, -28, 11, 31, -52, 0, -12, 1, -18, + -3, 127, 92, 11, 30, -23, -8, -26, -1, 23, 11, 14, 47, 42, 37, 57, + -7, -32, 11, -3, -16, -3, -57, 18, 7, -53, -107, -33, 42, 13, -40, 15, + 48, 11, 7, 60, -54, 37, -23, -32, -12, -3, -63, 38, -75, 75, -1, -39, + -69, 56, -10, 31, -11, 60, 38, 53, 77, 52, 37, -89, 64, -48, 87, 48, + -71, -43, -35, -61, -35, -75, 45, -61, -11, -61, -91, 20, -60, -9, 18, 121, + -57, 25, 22, 13, 36, -26, 27, 11, 22, -13, 11, 9, -20, -40, -10, -51, + -2, 74, 18, -76, -40, -3, 96, 1, 21, -34, -18, 127, 16, -9, -62, 30, + 45, -20, -5, 54, 39, -48, 66, 24, 25, 30, -18, -30, -54, -52, 55, 14, + -14, -52, 76, -45, -31, 36, -18, -87, -4, 21, -26, -73, -35, 5, 6, 30, + -12, -53, -52, 12, -26, 68, -51, 45, 35, 13, -63, 59, 1, 23, 37, 15, + -41, 22, 31, 24, -14, 127, 22, 17, -52, 14, -17, 68, -11, 47, -74, 3, + 27, 36, -27, -28, 1, 2, -39, -83, -30, 51, -45, -25, 0, -49, 34, -29, + 19, 42, -45, -8, -3, -5, 63, 31, 31, -31, -75, -14, -16, 12, 6, 26, + -34, 57, 3, -2, -24, -19, 10, -5, 127, -17, -45, 2, 16, -37, -12, -52, + 12, -2, 62, -44, -7, 45, 90, 13, -61, -4, 11, 41, 71, 4, -27, 13, + 8, 55, -19, 53, -87, -11, 29, 58, 120, -18, 12, 20, 62, 4, -30, -44, + -83, -14, -28, 11, 13, -83, 67, 20, 38, -39, -79, -42, 82, 40, -74, 83, + -33, 12, -45, -30, 24, 75, -38, 43, 127, 55, -31, 81, 25, -32, 27, 41, + -24, 15, 89, -91, 0, 16, -29, 53, 52, -24, 44, 68, -18, 35, -108, -34, + -19, 21, 26, -8, -51, 18, -20, 28, 53, 33, -15, 56, -24, -20, 0, -12, + 19, -16, -15, 11, 28, -19, 11, 11, 37, -49, -26, -1, -16, -13, -1, -11, + -32, 11, 10, 1, 4, 28, -14, 30, 127, 16, -32, 44, 12, -23, 30, -32, + 19, 34, 25, -59, 9, -33, -25, 10, -8, -43, -7, 0, 22, 29, -30, 41, + 82, -10, -71, -63, -32, 4, -67, -58, 42, -63, -38, -50, -32, 26, -46, 24, + -40, -42, -19, 38, 67, 63, -35, 57, 1, 18, 36, 82, -76, -28, 1, -65, + 36, 1, 15, -47, 31, -32, 60, -53, 42, -26, -32, -46, -43, 46, 48, 49, + 23, 36, -25, -2, 60, 67, 47, -95, -57, 127, -28, -4, 1, -10, 25, -28, + 58, 28, 127, 2, -75, -25, -28, -6, -25, 53, -8, -13, 15, -75, 6, 78, + -58, 49, 88, 24, -1, -41, -57, 24, 40, 71, 5, -23, 73, 33, 51, -8, + -53, -56, -11, -77, -64, -21, -104, 20, 108, 1, 1, 93, 68, -54, -52, -45, + -43, -20, 40, -54, -58, -46, -69, -47, -79, -75, 3, 59, -43, 73, 28, -27, + 41, 21, -74, -33, 43, 30, -37, 45, -7, -31, -35, 1, 29, -15, -125, -29, + -14, 22, 2, 31, 80, 81, -30, 24, 67, -2, 37, 81, -57, 1, -49, -10, + 2, -29, -56, 53, -16, 10, -51, -23, 69, 24, -25, -66, 46, 87, 42, 1, + -55, -10, 48, 4, -24, 45, 6, -102, 1, 27, 52, 127, 10, -14, 38, 79, + 67, 26, -16, 79, -23, -5, -53, -25, 13, -4, -19, -85, -23, 18, 59, -62, + 16, 70, -42, -37, -60, 40, 32, -48, 33, -59, -78, 59, 24, -16, 39, 85, + 8, -77, 46, 62, -33, 53, 88, 37, 84, -31, -127, -10, -68, -81, -72, 8, + -24, -77, 3, -55, 56, -4, 24, -10, -54, -26, 34, -34, -21, 48, -16, 63, + -118, -78, 46, 53, 38, 16, 21, 88, 73, 53, -15, 30, 79, -8, 34, 3, + 35, 60, -68, -36, 18, -6, -37, -51, 50, -8, -70, -71, 81, 100, -16, -51, + -23, -19, -17, 72, -52, -24, -4, -45, -37, 68, 39, -27, 62, -57, -40, -42, + -10, 1, 80, 7, 70, 1, -20, 84, 127, -70, -66, -5, -8, -34, 83, 24, + -56, 10, 6, -22, 24, 86, -17, 127, -74, -55, -19, 23, -77, 54, -12, 72, + 6, -54, 76, -14, -1, 16, -109, 26, -19, 125, 46, -7, -54, -17, -4, 22, + 22, -41, 27, 2, -7, -44, -24, -40, -52, -36, -38, -24, 85, 41, 28, -2, + 106, 17, -87, 64, 4, 70, 6, -47, -1, 26, -57, 29, -17, 33, 46, -24, + -46, -33, 91, -31, 12, -1, 9, 0, 44, 19, 4, -51, 25, 51, -59, 53, + 4, 27, -20, 18, 45, 3, -53, 18, 37, 19, 52, 57, 59, -36, -60, 2, + 14, 17, 6, -13, 39, -75, -57, -92, -8, 26, 51, -59, 70, 85, -8, -49, + 1, -5, -57, 52, -4, 20, -89, -61, 6, 71, -62, -47, -91, 8, 127, 0 +}; + +const int32_t Pw3Bias[64] = +{ + -2469, 372, 5107, -2590, 173, 1880, 1005, -1340, + -641, 3303, 2509, 638, -3712, 231, 159, -1769, + 2325, 435, -616, 164, -345, -2009, 2756, 1846, + -5011, 1225, -2706, -308, -4998, -3662, 3113, 585, + -4826, 3660, 885, -1038, 3053, 1462, -971, 1952, + -659, -1990, 221, 5004, -620, -3223, -1388, -1360, + -1173, -794, -74, -2363, -1115, -1368, 1178, -3527, + -1325, 2695, 328, -2186, 1121, -2674, -1134, -816 +}; + +const int32_t Pw3Multipliers[64] = +{ + 2125623454, 1685397840, 1451160505, 1212845682, 2111261334, 2120779924, 1134031096, 1982012215, + 1106467129, 1743067892, 1914227926, 1911795518, 1395728237, 1871482809, 1107232945, 1115789170, + 1861668603, 1637506218, 1617400246, 1104462578, 1171061685, 1945788541, 1972228465, 1115893105, + 1915076393, 1148359703, 1537363116, 2077991104, 2122637176, 1814959105, 1178325056, 1779914612, + 1323246584, 1411560512, 2035307578, 1229639304, 1887867935, 1369819652, 2011466042, 1549539533, + 1662219091, 1161880829, 1989103605, 1650529291, 1925129379, 2133933992, 1806622187, 1949553996, + 1801398466, 1417207901, 1514088356, 1338945373, 2029868740, 1075425059, 1996698370, 1388902233, + 1343216239, 1283390375, 1563540710, 1808001767, 1147744695, 1925992791, 2144067816, 1144746982 +}; + +const int32_t Pw3Shifts[64] = +{ + -9, -8, -9, -8, -9, -9, -8, -9, + -8, -9, -9, -9, -8, -8, -8, -8, + -9, -9, -9, -8, -8, -9, -9, -8, + -9, -8, -8, -9, -9, -9, -8, -9, + -8, -9, -9, -8, -9, -8, -9, -9, + -9, -8, -9, -9, -9, -9, -9, -9, + -9, -8, -8, -8, -9, -8, -9, -9, + -8, -8, -9, -9, -8, -9, -9, -8 +}; + +const int8_t DenseWeights[768] = +{ + -102, -11, 91, -63, -24, -61, -105, 91, -40, 42, 9, -66, -65, -84, 28, -41, + -20, -50, -79, 118, -55, 45, -31, 68, 53, 30, -67, 63, -69, 4, 25, 43, + 46, -48, 9, -98, -22, -18, -14, 57, 1, -6, 108, -17, -3, -31, -8, 27, + -20, -44, -28, 36, 11, -6, -54, -127, 14, -82, 70, -91, -22, 32, 97, 67, + -56, 53, 49, -68, 52, 47, -61, -51, -77, 43, 20, -67, -43, 57, 81, 40, + 99, -87, -5, 32, -89, -84, 46, 71, -42, -71, -127, 73, 0, -73, 103, -30, + -93, 9, -34, -64, -10, -55, 88, -43, 29, -100, 27, 83, 74, -96, -89, -50, + 65, 55, -76, -83, 111, -115, 112, -69, 34, 46, -63, -11, 63, -60, -45, -100, + -13, 27, -26, 46, 32, 6, 20, 17, 102, -42, 45, 42, 60, -85, -125, -70, + -43, 29, 25, -58, 101, 28, 30, -14, -20, 79, 54, -67, -41, 15, 55, -83, + -62, 77, -79, 44, 87, 77, -29, 21, -39, 75, -127, 51, -69, -67, -61, -60, + 5, -116, 13, 9, -25, -82, -17, 12, -61, -56, -3, -45, -78, 45, -69, 32, + -71, 33, 11, -17, -62, -48, -78, -119, 73, 103, 66, -4, -118, 3, 115, -87, + -1, -96, 106, 9, 77, -18, 15, -28, -51, 52, -15, -101, 89, -27, -76, -110, + -121, 88, 96, -47, -10, 54, 89, 116, -34, -121, 25, 56, -60, 1, -65, 64, + -34, 35, -107, 27, 50, 106, 72, -105, -127, 30, -37, -90, -46, -32, 83, -83, + -68, 34, 56, 94, -39, -103, -27, -84, 53, -74, -59, -44, 30, 92, 49, -94, + 79, 87, -85, -96, -45, 81, 81, -86, -30, 53, -89, -63, -88, -47, -29, -40, + 8, -49, -35, 107, -60, -29, -127, -96, -7, 110, 26, -7, 22, 24, -23, -92, + -62, -76, 70, -38, 24, 22, 85, 85, 102, -57, -30, -9, 84, 86, -87, -81, + -17, -110, -35, -99, 63, -51, 42, 52, -2, 18, -84, -127, 46, -126, 78, 20, + -49, 2, -89, -37, -66, -79, -50, -23, 100, -97, 41, -20, -60, 81, -107, 124, + 67, -16, -89, 81, -101, -48, -82, -27, 110, 39, -28, -38, -38, 30, 44, -82, + -86, 92, 17, -37, 75, 50, 79, 94, 95, -23, 83, 111, -89, 84, 13, -72, + 23, -74, -54, -51, 108, 48, 87, 32, 56, -108, 116, -38, 22, -66, -87, -86, + -47, -5, 38, -70, 42, 117, -35, 13, 86, -104, 104, -31, 94, -84, 124, -53, + 85, -92, -58, -35, -88, -41, 111, 85, -48, -37, -90, -73, 106, -14, 0, -80, + 57, -39, 13, -85, -103, -68, -53, -5, -127, -45, -21, -24, 54, 31, -50, -4, + 96, -28, -63, 98, -69, -61, -114, 42, -100, -91, -89, 63, 47, 63, -99, -95, + 85, -23, 27, 93, 59, -53, -21, 99, -60, -81, 45, -12, -1, 101, -61, -66, + -50, 48, 85, -25, -33, -87, -86, -127, -14, 19, 73, 55, 59, -73, 80, 46, + 54, -90, 22, 24, -38, 19, -107, -6, 23, 26, 15, -24, -51, -120, 66, -76, + 36, 10, -45, -71, 103, -114, -56, -70, -99, -111, -39, -87, -78, -1, -109, 29, + 71, 103, -72, -3, 99, -127, 63, 68, -118, 3, 43, -21, 30, -65, -126, -47, + -39, 54, -73, 0, 87, -81, -38, -53, 60, 42, 40, 27, 36, 46, -91, -55, + -111, 9, 98, 68, -108, 43, 100, 31, 29, 50, 83, 55, 55, -82, -113, -60, + -46, -94, -49, -70, -33, -55, 71, 24, 100, 106, -71, 88, -18, 35, -108, 110, + -74, 69, 69, -72, -112, 74, -106, -104, -123, 90, -68, 63, -16, -80, 50, 54, + 15, 111, -46, 14, 8, 59, -92, 77, -25, 43, -88, 16, -10, -43, 127, -67, + -38, -96, -105, -116, 8, 95, 26, 81, 69, 63, 64, -56, -102, -109, 27, 11, + 75, 88, -71, -84, -83, 2, -92, -56, -35, -97, -7, 46, 96, -25, -78, 70, + -52, 15, 65, -113, -31, 10, -108, -50, 24, -71, 37, -118, 69, -7, -93, -127, + 88, -64, 9, -68, -15, -67, -34, -121, -14, -61, -25, -56, -19, -9, -70, -62, + 19, 1, -30, 70, 91, 65, -51, 30, -37, -51, 4, 53, 55, -102, 37, -26, + 79, -75, 34, 32, 16, -7, 127, -49, -77, -54, -81, 86, -2, 67, 24, 80, + 33, -93, -82, -13, -61, 7, 12, -102, 63, -28, 58, 100, 1, -92, -23, -49, + 70, -65, -70, 100, 40, 109, 35, -32, -88, 49, -8, -19, 37, 127, -51, 120, + 97, 104, 19, -48, -33, -59, -24, -111, -75, 113, -63, 76, -47, -1, 100, 76 +}; + +const int32_t DenseBias[12] = +{ + -19, 184, 0, -86, -709, -358, -190, -267, + 128, -472, 164, 635 +}; + +const int32_t DenseMultipliers[12] = +{ + 1530234239, 1321088838, 1594658568, 1197411415, 1319435029, 1256692741, 1317342258, 1472497376, + 1364937572, 1320595705, 1967501714, 1155829002 +}; + +const int32_t DenseShifts[12] = +{ + -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10 +}; + + const ConvLayerData Stem = { StemWeights, StemBias, StemMultipliers, StemShifts, { 0.5723904371f, 88 }, { 0.0638487637f, -128 }, true }; + + const ConvLayerData Depthwise[BlockCount] = + { + { Dw0Weights, Dw0Bias, Dw0Multipliers, Dw0Shifts, { 0.0638487637f, -128 }, { 0.08065630496f, -128 }, true }, + { Dw1Weights, Dw1Bias, Dw1Multipliers, Dw1Shifts, { 0.1159228757f, -128 }, { 0.06722784787f, -128 }, true }, + { Dw2Weights, Dw2Bias, Dw2Multipliers, Dw2Shifts, { 0.1234830692f, -128 }, { 0.04396178946f, -128 }, true }, + { Dw3Weights, Dw3Bias, Dw3Multipliers, Dw3Shifts, { 0.1188071072f, -128 }, { 0.04403752834f, -128 }, true } + }; + + const ConvLayerData Pointwise[BlockCount] = + { + { Pw0Weights, Pw0Bias, Pw0Multipliers, Pw0Shifts, { 0.08065630496f, -128 }, { 0.186380282f, -32 }, false }, + { Pw1Weights, Pw1Bias, Pw1Multipliers, Pw1Shifts, { 0.06722784787f, -128 }, { 0.1928178221f, -36 }, false }, + { Pw2Weights, Pw2Bias, Pw2Multipliers, Pw2Shifts, { 0.04396178946f, -128 }, { 0.1832210124f, -38 }, false }, + { Pw3Weights, Pw3Bias, Pw3Multipliers, Pw3Shifts, { 0.04403752834f, -128 }, { 0.1991460323f, -46 }, false } + }; + + const AddLayerData Adds[BlockCount] = + { + { { 0.0638487637f, -128 }, { 0.186380282f, -32 }, { 0.1159228757f, -128 }, 1471337788, -2, 1073741824, 0, 1726357311, -18, 20 }, + { { 0.1159228757f, -128 }, { 0.1928178221f, -36 }, { 0.1234830692f, -128 }, 1291076091, -1, 1073741824, 0, 1676639245, -18, 20 }, + { { 0.1234830692f, -128 }, { 0.1832210124f, -38 }, { 0.1188071072f, -128 }, 1447311466, -1, 1073741824, 0, 1655894741, -18, 20 }, + { { 0.1188071072f, -128 }, { 0.1991460323f, -46 }, { 0.1347524226f, -128 }, 1281151912, -1, 1073741824, 0, 1586846603, -18, 20 } + }; + + const MeanLayerData GlobalMean = + { + { 0.1347524226f, -128 }, + { 0.02445821837f, -128 }, + 757219174, + -3, + 125 + }; + + const ConvLayerData Dense = { DenseWeights, DenseBias, DenseMultipliers, DenseShifts, { 0.02445821837f, -128 }, { 0.1747612506f, 20 }, false }; + const Quantization ModelInput = { 0.5723904371f, 88 }; + const Quantization ModelOutput = { 0.1747612506f, 20 }; +} +} diff --git a/src/Apps/Game/src/recognition/ResBnKwsModelData.h b/src/Apps/Game/src/recognition/ResBnKwsModelData.h new file mode 100644 index 0000000..17b401b --- /dev/null +++ b/src/Apps/Game/src/recognition/ResBnKwsModelData.h @@ -0,0 +1,106 @@ +#pragma once + +#include +#include + +namespace Game +{ +namespace ResBnKwsModelData +{ + const size_t InputFrameCount = 49; + const size_t InputMfccCount = 10; + const size_t ChannelCount = 64; + const size_t ClassCount = 12; + const size_t BlockCount = 4; + + struct Quantization + { + float scale; + int32_t zeroPoint; + }; + + struct ConvLayerData + { + const int8_t* weights; + const int32_t* bias; + const int32_t* multipliers; + const int32_t* shifts; + Quantization input; + Quantization output; + bool relu; + }; + + struct AddLayerData + { + Quantization input0; + Quantization input1; + Quantization output; + int32_t input0Multiplier; + int32_t input0Shift; + int32_t input1Multiplier; + int32_t input1Shift; + int32_t outputMultiplier; + int32_t outputShift; + int32_t leftShift; + }; + + struct MeanLayerData + { + Quantization input; + Quantization output; + int32_t multiplier; + int32_t shift; + int32_t elementCount; + }; + + extern const int8_t StemWeights[2560]; + extern const int32_t StemBias[64]; + extern const int32_t StemMultipliers[64]; + extern const int32_t StemShifts[64]; + extern const int8_t Dw0Weights[576]; + extern const int32_t Dw0Bias[64]; + extern const int32_t Dw0Multipliers[64]; + extern const int32_t Dw0Shifts[64]; + extern const int8_t Dw1Weights[576]; + extern const int32_t Dw1Bias[64]; + extern const int32_t Dw1Multipliers[64]; + extern const int32_t Dw1Shifts[64]; + extern const int8_t Dw2Weights[576]; + extern const int32_t Dw2Bias[64]; + extern const int32_t Dw2Multipliers[64]; + extern const int32_t Dw2Shifts[64]; + extern const int8_t Dw3Weights[576]; + extern const int32_t Dw3Bias[64]; + extern const int32_t Dw3Multipliers[64]; + extern const int32_t Dw3Shifts[64]; + extern const int8_t Pw0Weights[4096]; + extern const int32_t Pw0Bias[64]; + extern const int32_t Pw0Multipliers[64]; + extern const int32_t Pw0Shifts[64]; + extern const int8_t Pw1Weights[4096]; + extern const int32_t Pw1Bias[64]; + extern const int32_t Pw1Multipliers[64]; + extern const int32_t Pw1Shifts[64]; + extern const int8_t Pw2Weights[4096]; + extern const int32_t Pw2Bias[64]; + extern const int32_t Pw2Multipliers[64]; + extern const int32_t Pw2Shifts[64]; + extern const int8_t Pw3Weights[4096]; + extern const int32_t Pw3Bias[64]; + extern const int32_t Pw3Multipliers[64]; + extern const int32_t Pw3Shifts[64]; + extern const int8_t DenseWeights[768]; + extern const int32_t DenseBias[12]; + extern const int32_t DenseMultipliers[12]; + extern const int32_t DenseShifts[12]; + + extern const ConvLayerData Stem; + extern const ConvLayerData Depthwise[BlockCount]; + extern const ConvLayerData Pointwise[BlockCount]; + extern const AddLayerData Adds[BlockCount]; + extern const MeanLayerData GlobalMean; + extern const ConvLayerData Dense; + extern const Quantization ModelInput; + extern const Quantization ModelOutput; +} +} diff --git a/src/Apps/Game/src/recognition/ResBnKwsRecognizer.cpp b/src/Apps/Game/src/recognition/ResBnKwsRecognizer.cpp new file mode 100644 index 0000000..4c88d64 --- /dev/null +++ b/src/Apps/Game/src/recognition/ResBnKwsRecognizer.cpp @@ -0,0 +1,1130 @@ +#include "ResBnKwsRecognizer.h" +#include "ResBnKwsModelData.h" +#include "../audio/VoiceEffect.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + const float Pi = 3.14159265358979323846f; + const uint32_t TargetSampleRate = 16000u; + const uint32_t TargetChannels = 1u; + const size_t WindowSamples = 16000u; + const size_t FftSize = 512u; + const size_t SpectrumBins = FftSize / 2u + 1u; + const size_t FrameStepSamples = 320u; + const size_t FeatureFrameCount = 49u; + const size_t MelBinCount = 40u; + const size_t MfccBinCount = 10u; + const size_t ClassCount = 12u; + const size_t ActivationHeight = 25u; + const size_t ActivationWidth = 5u; + const size_t ActivationChannels = 64u; + const size_t ActivationElementCount = + ActivationHeight * ActivationWidth * ActivationChannels; + const size_t InvalidClass = static_cast(-1); + + struct MelEnergyCache + { + size_t frameCount; + std::vector values; + + MelEnergyCache() : frameCount(0u) + { + } + }; + + struct FusionState + { + bool hasSmoothedLogits; + size_t currentClass; + size_t consecutiveHits; + std::vector smoothedLogits; + Game::KeywordRecognitionResult best; + + FusionState() + : hasSmoothedLogits(false), + currentClass(InvalidClass), + consecutiveHits(0u), + smoothedLogits(ClassCount, 0.0f) + { + } + }; + + static float HertzToMel(float hertz) + { + return 1127.0f * std::log(1.0f + hertz / 700.0f); + } + + static Game::KeywordCommand CommandFromClass(size_t classIndex) + { + switch (classIndex) + { + case 0: + return Game::KeywordCommand::Down; + case 1: + return Game::KeywordCommand::Go; + case 2: + return Game::KeywordCommand::Left; + case 3: + return Game::KeywordCommand::No; + case 4: +#if defined(RESBN_KWS_HAS_OFF_COMMAND) + return Game::KeywordCommand::Off; +#else + return Game::KeywordCommand::None; +#endif + case 5: + return Game::KeywordCommand::On; + case 6: + return Game::KeywordCommand::Right; + case 7: + return Game::KeywordCommand::Stop; + case 8: + return Game::KeywordCommand::Up; + case 9: + return Game::KeywordCommand::Yes; + case 10: + case 11: + default: + return Game::KeywordCommand::None; + } + } + + static const std::vector& GetHannWindow() + { + static std::vector window; + if (!window.empty()) + { + return window; + } + + window.resize(FftSize, 0.0f); + for (size_t i = 0; i < FftSize; ++i) + { + window[i] = + 0.5f - + 0.5f * std::cos( + (2.0f * Pi * static_cast(i)) / + static_cast(FftSize - 1u)); + } + return window; + } + + static const std::vector& GetMelFilterBank() + { + static std::vector filters; + if (!filters.empty()) + { + return filters; + } + + filters.assign(MelBinCount * SpectrumBins, 0.0f); + const float minMel = HertzToMel(20.0f); + const float maxMel = HertzToMel(4000.0f); + std::vector melPoints(MelBinCount + 2u, 0.0f); + + for (size_t i = 0; i < melPoints.size(); ++i) + { + const float t = + static_cast(i) / + static_cast(melPoints.size() - 1u); + melPoints[i] = minMel + (maxMel - minMel) * t; + } + + for (size_t mel = 0; mel < MelBinCount; ++mel) + { + const float left = melPoints[mel]; + const float center = melPoints[mel + 1u]; + const float right = melPoints[mel + 2u]; + + for (size_t bin = 0; bin < SpectrumBins; ++bin) + { + const float frequency = + static_cast(bin) * + static_cast(TargetSampleRate) / + static_cast(FftSize); + const float frequencyMel = HertzToMel(frequency); + const float lowerSlope = + (frequencyMel - left) / (center - left); + const float upperSlope = + (right - frequencyMel) / (right - center); + const float weight = + std::max(0.0f, std::min(lowerSlope, upperSlope)); + filters[mel * SpectrumBins + bin] = weight; + } + } + return filters; + } + + static const std::vector& GetDctMatrix() + { + static std::vector matrix; + if (!matrix.empty()) + { + return matrix; + } + + matrix.resize(MfccBinCount * MelBinCount, 0.0f); + for (size_t coefficient = 0; + coefficient < MfccBinCount; + ++coefficient) + { + for (size_t mel = 0; mel < MelBinCount; ++mel) + { + const float angle = + Pi * + (static_cast(mel) + 0.5f) * + static_cast(coefficient) / + static_cast(MelBinCount); + matrix[coefficient * MelBinCount + mel] = + std::cos(angle); + } + } + return matrix; + } + + static void Fft(std::vector >& data) + { + const size_t count = data.size(); + for (size_t i = 1u, j = 0u; i < count; ++i) + { + size_t bit = count >> 1u; + for (; (j & bit) != 0u; bit >>= 1u) + { + j ^= bit; + } + j ^= bit; + if (i < j) + { + std::swap(data[i], data[j]); + } + } + + for (size_t length = 2u; length <= count; length <<= 1u) + { + const float angle = -2.0f * Pi / static_cast(length); + const std::complex step(std::cos(angle), std::sin(angle)); + for (size_t offset = 0u; offset < count; offset += length) + { + std::complex factor(1.0f, 0.0f); + for (size_t i = 0u; i < length / 2u; ++i) + { + const std::complex even = data[offset + i]; + const std::complex odd = + data[offset + i + length / 2u] * factor; + data[offset + i] = even + odd; + data[offset + i + length / 2u] = even - odd; + factor *= step; + } + } + } + } + + static std::vector PrepareAudio( + const std::vector& samples, + uint32_t sampleRate, + uint32_t channels) + { + if (samples.empty() || sampleRate == 0u || channels == 0u) + { + return std::vector(); + } + + std::vector prepared = samples; + uint32_t preparedChannels = channels; + uint32_t preparedSampleRate = sampleRate; + + if (preparedChannels != TargetChannels) + { + prepared = Game::VoiceEffect::convert_channels( + prepared, + preparedChannels, + TargetChannels); + preparedChannels = TargetChannels; + } + + if (preparedSampleRate != TargetSampleRate) + { + prepared = Game::VoiceEffect::resample( + prepared, + preparedSampleRate, + TargetSampleRate, + preparedChannels); + } + + std::vector trimmed = + Game::VoiceEffect::trim_silence(prepared, 0.02f, TargetChannels); + return trimmed.empty() ? prepared : trimmed; + } + + static std::vector PadToMinimumWindow( + const std::vector& samples) + { + if (samples.size() >= WindowSamples) + { + return samples; + } + std::vector padded = samples; + padded.resize(WindowSamples, 0); + return padded; + } + + static MelEnergyCache ExtractMelEnergyCache( + const std::vector& samples) + { + MelEnergyCache cache; + if (samples.size() < FftSize) + { + return cache; + } + + cache.frameCount = + 1u + (samples.size() - FftSize) / FrameStepSamples; + cache.values.assign(cache.frameCount * MelBinCount, 0.0f); + + const std::vector& hann = GetHannWindow(); + const std::vector& filters = GetMelFilterBank(); + std::vector > fftBuffer(FftSize); + std::vector spectrum(SpectrumBins, 0.0f); + + for (size_t frame = 0; frame < cache.frameCount; ++frame) + { + const size_t sampleOffset = frame * FrameStepSamples; + for (size_t i = 0; i < FftSize; ++i) + { + fftBuffer[i] = std::complex( + static_cast(samples[sampleOffset + i]) * hann[i], + 0.0f); + } + Fft(fftBuffer); + + for (size_t bin = 0; bin < SpectrumBins; ++bin) + { + spectrum[bin] = std::abs(fftBuffer[bin]); + } + + for (size_t mel = 0; mel < MelBinCount; ++mel) + { + float energy = 0.0f; + for (size_t bin = 0; bin < SpectrumBins; ++bin) + { + energy += filters[mel * SpectrumBins + bin] * spectrum[bin]; + } + cache.values[frame * MelBinCount + mel] = energy; + } + } + return cache; + } + + static int32_t WindowMaxAbs( + const std::vector& samples, + size_t sampleStart) + { + int32_t maximum = 0; + const size_t sampleEnd = + std::min(samples.size(), sampleStart + WindowSamples); + for (size_t i = sampleStart; i < sampleEnd; ++i) + { + maximum = std::max( + maximum, + std::abs(static_cast(samples[i]))); + } + return maximum; + } + + static std::vector BuildMfccWindow( + const MelEnergyCache& cache, + const std::vector& samples, + size_t frameStart, + float gain) + { + std::vector features( + FeatureFrameCount * MfccBinCount, + 0.0f); + const size_t sampleStart = frameStart * FrameStepSamples; + const int32_t maxAbs = WindowMaxAbs(samples, sampleStart); + if (maxAbs == 0) + { + return features; + } + + const float amplitudeScale = + gain / static_cast(maxAbs); + const std::vector& dct = GetDctMatrix(); + const float dctNormalization = + std::sqrt(2.0f / static_cast(MelBinCount)); + std::vector logMel(MelBinCount, 0.0f); + + for (size_t frame = 0; frame < FeatureFrameCount; ++frame) + { + const size_t cacheFrame = frameStart + frame; + for (size_t mel = 0; mel < MelBinCount; ++mel) + { + const float energy = + cache.values[cacheFrame * MelBinCount + mel] * + amplitudeScale; + logMel[mel] = std::log(energy + 1.0e-6f); + } + + for (size_t coefficient = 0; + coefficient < MfccBinCount; + ++coefficient) + { + float value = 0.0f; + for (size_t mel = 0; mel < MelBinCount; ++mel) + { + value += + logMel[mel] * + dct[coefficient * MelBinCount + mel]; + } + features[frame * MfccBinCount + coefficient] = + value * dctNormalization; + } + } + return features; + } + + static size_t Offset( + size_t width, + size_t channels, + size_t y, + size_t x, + size_t channel) + { + return (y * width + x) * channels + channel; + } + + static int ComputePaddingBefore( + size_t inputSize, + size_t outputSize, + size_t filterSize, + size_t stride) + { + const int required = + static_cast((outputSize - 1u) * stride + filterSize); + const int totalPadding = + std::max(0, required - static_cast(inputSize)); + return totalPadding / 2; + } + + static int32_t SaturatingCastInt32(int64_t value) + { + if (value > std::numeric_limits::max()) + { + return std::numeric_limits::max(); + } + if (value < std::numeric_limits::min()) + { + return std::numeric_limits::min(); + } + return static_cast(value); + } + + static int32_t SaturatingRoundingDoublingHighMul( + int32_t a, + int32_t b) + { + const bool overflow = + a == std::numeric_limits::min() && a == b; + const int64_t product = + static_cast(a) * static_cast(b); + const int64_t nudge = + product >= 0 + ? static_cast(1) << 30 + : 1 - (static_cast(1) << 30); + const int32_t result = static_cast( + (product + nudge) / (static_cast(1) << 31)); + return overflow + ? std::numeric_limits::max() + : result; + } + + static int32_t RoundingDivideByPowerOfTwo( + int32_t value, + int exponent) + { + if (exponent <= 0) + { + return value; + } + const uint32_t mask = + (static_cast(1) << exponent) - 1u; + const int32_t remainder = + static_cast(static_cast(value) & mask); + const int32_t threshold = + static_cast(mask >> 1u) + (value < 0 ? 1 : 0); + return (value >> exponent) + (remainder > threshold ? 1 : 0); + } + + static int32_t MultiplyByQuantizedMultiplier( + int32_t value, + int32_t multiplier, + int shift) + { + const int leftShift = shift > 0 ? shift : 0; + const int rightShift = shift > 0 ? 0 : -shift; + const int32_t shifted = SaturatingCastInt32( + static_cast(value) * + (static_cast(1) << leftShift)); + return RoundingDivideByPowerOfTwo( + SaturatingRoundingDoublingHighMul(shifted, multiplier), + rightShift); + } + + static int8_t ClampInt8(int32_t value, int32_t minimum, int32_t maximum) + { + return static_cast( + std::max(minimum, std::min(maximum, value))); + } + + static int8_t QuantizeFloat( + float value, + const Game::ResBnKwsModelData::Quantization& quantization) + { + const int32_t quantized = + static_cast( + std::nearbyint(value / quantization.scale)) + + quantization.zeroPoint; + return ClampInt8(quantized, -128, 127); + } + + static void Conv2DInt8( + const int8_t* input, + size_t inputHeight, + size_t inputWidth, + size_t inputChannels, + const Game::ResBnKwsModelData::ConvLayerData& layer, + size_t outputChannels, + size_t filterHeight, + size_t filterWidth, + size_t strideY, + size_t strideX, + int8_t* output, + size_t outputHeight, + size_t outputWidth) + { + const int padY = + ComputePaddingBefore(inputHeight, outputHeight, filterHeight, strideY); + const int padX = + ComputePaddingBefore(inputWidth, outputWidth, filterWidth, strideX); + const int32_t activationMinimum = + layer.relu ? std::max(-128, layer.output.zeroPoint) : -128; + + for (size_t outputY = 0; outputY < outputHeight; ++outputY) + { + for (size_t outputX = 0; outputX < outputWidth; ++outputX) + { + for (size_t outputChannel = 0; + outputChannel < outputChannels; + ++outputChannel) + { + int32_t accumulator = layer.bias[outputChannel]; + for (size_t kernelY = 0; kernelY < filterHeight; ++kernelY) + { + const int inputY = + static_cast(outputY * strideY + kernelY) - padY; + if (inputY < 0 || inputY >= static_cast(inputHeight)) + { + continue; + } + for (size_t kernelX = 0; kernelX < filterWidth; ++kernelX) + { + const int inputX = + static_cast(outputX * strideX + kernelX) - padX; + if (inputX < 0 || inputX >= static_cast(inputWidth)) + { + continue; + } + for (size_t inputChannel = 0; + inputChannel < inputChannels; + ++inputChannel) + { + const size_t inputIndex = + Offset( + inputWidth, + inputChannels, + static_cast(inputY), + static_cast(inputX), + inputChannel); + const size_t weightIndex = + ((outputChannel * filterHeight + kernelY) * + filterWidth + + kernelX) * + inputChannels + + inputChannel; + const int32_t inputValue = + static_cast(input[inputIndex]) - + layer.input.zeroPoint; + accumulator += + inputValue * + static_cast(layer.weights[weightIndex]); + } + } + } + + int32_t quantized = MultiplyByQuantizedMultiplier( + accumulator, + layer.multipliers[outputChannel], + layer.shifts[outputChannel]); + quantized += layer.output.zeroPoint; + output[Offset( + outputWidth, + outputChannels, + outputY, + outputX, + outputChannel)] = + ClampInt8(quantized, activationMinimum, 127); + } + } + } + } + + static void DepthwiseConv2DInt8( + const int8_t* input, + size_t height, + size_t width, + size_t channels, + const Game::ResBnKwsModelData::ConvLayerData& layer, + int8_t* output) + { + const size_t filterHeight = 3u; + const size_t filterWidth = 3u; + const int padY = + ComputePaddingBefore(height, height, filterHeight, 1u); + const int padX = + ComputePaddingBefore(width, width, filterWidth, 1u); + const int32_t activationMinimum = + layer.relu ? std::max(-128, layer.output.zeroPoint) : -128; + + for (size_t y = 0; y < height; ++y) + { + for (size_t x = 0; x < width; ++x) + { + for (size_t channel = 0; channel < channels; ++channel) + { + int32_t accumulator = layer.bias[channel]; + for (size_t kernelY = 0; kernelY < filterHeight; ++kernelY) + { + const int inputY = + static_cast(y + kernelY) - padY; + if (inputY < 0 || inputY >= static_cast(height)) + { + continue; + } + for (size_t kernelX = 0; kernelX < filterWidth; ++kernelX) + { + const int inputX = + static_cast(x + kernelX) - padX; + if (inputX < 0 || inputX >= static_cast(width)) + { + continue; + } + const size_t inputIndex = + Offset( + width, + channels, + static_cast(inputY), + static_cast(inputX), + channel); + const size_t weightIndex = + (kernelY * filterWidth + kernelX) * + channels + + channel; + const int32_t inputValue = + static_cast(input[inputIndex]) - + layer.input.zeroPoint; + accumulator += + inputValue * + static_cast(layer.weights[weightIndex]); + } + } + + int32_t quantized = MultiplyByQuantizedMultiplier( + accumulator, + layer.multipliers[channel], + layer.shifts[channel]); + quantized += layer.output.zeroPoint; + output[Offset(width, channels, y, x, channel)] = + ClampInt8(quantized, activationMinimum, 127); + } + } + } + } + + static void AddInt8( + const int8_t* input0, + const int8_t* input1, + size_t count, + const Game::ResBnKwsModelData::AddLayerData& layer, + int8_t* output) + { + const int32_t activationMinimum = + std::max(-128, layer.output.zeroPoint); + for (size_t i = 0; i < count; ++i) + { + int32_t value0 = + static_cast(input0[i]) - + layer.input0.zeroPoint; + int32_t value1 = + static_cast(input1[i]) - + layer.input1.zeroPoint; + value0 = SaturatingCastInt32( + static_cast(value0) * + (static_cast(1) << layer.leftShift)); + value1 = SaturatingCastInt32( + static_cast(value1) * + (static_cast(1) << layer.leftShift)); + value0 = MultiplyByQuantizedMultiplier( + value0, + layer.input0Multiplier, + layer.input0Shift); + value1 = MultiplyByQuantizedMultiplier( + value1, + layer.input1Multiplier, + layer.input1Shift); + int32_t quantized = MultiplyByQuantizedMultiplier( + value0 + value1, + layer.outputMultiplier, + layer.outputShift); + quantized += layer.output.zeroPoint; + output[i] = ClampInt8(quantized, activationMinimum, 127); + } + } + + static void GlobalMeanInt8( + const int8_t* input, + size_t height, + size_t width, + size_t channels, + int8_t* output) + { + const Game::ResBnKwsModelData::MeanLayerData& layer = + Game::ResBnKwsModelData::GlobalMean; + for (size_t channel = 0; channel < channels; ++channel) + { + int32_t sum = 0; + for (size_t y = 0; y < height; ++y) + { + for (size_t x = 0; x < width; ++x) + { + sum += + static_cast( + input[Offset(width, channels, y, x, channel)]) - + layer.input.zeroPoint; + } + } + const int32_t quantized = + MultiplyByQuantizedMultiplier( + sum, + layer.multiplier, + layer.shift) + + layer.output.zeroPoint; + output[channel] = ClampInt8(quantized, -128, 127); + } + } + + static void FullyConnectedInt8( + const int8_t* input, + int8_t* output) + { + const Game::ResBnKwsModelData::ConvLayerData& layer = + Game::ResBnKwsModelData::Dense; + for (size_t outputChannel = 0; + outputChannel < ClassCount; + ++outputChannel) + { + int32_t accumulator = layer.bias[outputChannel]; + for (size_t inputChannel = 0; + inputChannel < ActivationChannels; + ++inputChannel) + { + const int32_t inputValue = + static_cast(input[inputChannel]) - + layer.input.zeroPoint; + accumulator += + inputValue * + static_cast( + layer.weights[ + outputChannel * ActivationChannels + inputChannel]); + } + int32_t quantized = MultiplyByQuantizedMultiplier( + accumulator, + layer.multipliers[outputChannel], + layer.shifts[outputChannel]); + quantized += layer.output.zeroPoint; + output[outputChannel] = ClampInt8(quantized, -128, 127); + } + } + + static void Softmax( + const std::vector& logits, + std::vector& probabilities) + { + probabilities.assign(logits.size(), 0.0f); + if (logits.empty()) + { + return; + } + + float maximum = logits[0]; + for (size_t i = 1u; i < logits.size(); ++i) + { + maximum = std::max(maximum, logits[i]); + } + + float sum = 0.0f; + for (size_t i = 0u; i < logits.size(); ++i) + { + probabilities[i] = std::exp(logits[i] - maximum); + sum += probabilities[i]; + } + if (sum <= 0.0f) + { + return; + } + for (size_t i = 0u; i < probabilities.size(); ++i) + { + probabilities[i] /= sum; + } + } + + static void UpdateFusion( + FusionState& state, + const std::vector& logits, + float smoothingAlpha, + float confidenceThreshold, + float marginThreshold, + size_t requiredHits) + { + if (!state.hasSmoothedLogits) + { + state.smoothedLogits = logits; + state.hasSmoothedLogits = true; + } + else + { + for (size_t i = 0u; i < ClassCount; ++i) + { + state.smoothedLogits[i] = + smoothingAlpha * state.smoothedLogits[i] + + (1.0f - smoothingAlpha) * logits[i]; + } + } + + std::vector probabilities; + Softmax(state.smoothedLogits, probabilities); + size_t bestIndex = 0u; + size_t secondIndex = 1u; + if (probabilities[secondIndex] > probabilities[bestIndex]) + { + std::swap(bestIndex, secondIndex); + } + for (size_t i = 2u; i < probabilities.size(); ++i) + { + if (probabilities[i] > probabilities[bestIndex]) + { + secondIndex = bestIndex; + bestIndex = i; + } + else if (probabilities[i] > probabilities[secondIndex]) + { + secondIndex = i; + } + } + + const float confidence = probabilities[bestIndex]; + const float margin = confidence - probabilities[secondIndex]; + const Game::KeywordCommand command = CommandFromClass(bestIndex); + const bool valid = + command != Game::KeywordCommand::None && + confidence >= confidenceThreshold && + margin >= marginThreshold; + + if (!valid) + { + state.currentClass = InvalidClass; + state.consecutiveHits = 0u; + return; + } + + if (state.currentClass == bestIndex) + { + ++state.consecutiveHits; + } + else + { + state.currentClass = bestIndex; + state.consecutiveHits = 1u; + } + + if (state.consecutiveHits >= requiredHits && + confidence > state.best.confidence) + { + state.best = Game::KeywordRecognitionResult(command, confidence); + } + } +} + +namespace Game +{ + ResBnKwsRecognizer::ResBnKwsRecognizer() + : confidenceThreshold(0.75f), + marginThreshold(0.15f), + smoothingAlpha(0.60f), + inputGain(1.0f), + minConsecutiveHits(2u), + featureWindowStepFrames(10u), + initialized(false) + { + } + + ResBnKwsRecognizer::ResBnKwsRecognizer( + const std::string& unusedModelPath) + : confidenceThreshold(0.75f), + marginThreshold(0.15f), + smoothingAlpha(0.60f), + inputGain(1.0f), + minConsecutiveHits(2u), + featureWindowStepFrames(10u), + initialized(false) + { + (void)unusedModelPath; + } + + ResBnKwsRecognizer::~ResBnKwsRecognizer() + { + } + + bool ResBnKwsRecognizer::init() + { + if (initialized) + { + return true; + } + initialized = true; + return true; + } + + KeywordRecognitionResult ResBnKwsRecognizer::recognize( + const std::vector& samples, + uint32_t sampleRate, + uint32_t channels) + { + if (!initialized) + { + return KeywordRecognitionResult(); + } + + std::vector prepared = + PadToMinimumWindow(PrepareAudio(samples, sampleRate, channels)); + if (prepared.empty()) + { + return KeywordRecognitionResult(); + } + + const MelEnergyCache cache = ExtractMelEnergyCache(prepared); + if (cache.frameCount < FeatureFrameCount) + { + return KeywordRecognitionResult(); + } + + std::vector frameStarts; + for (size_t frameStart = 0u; + frameStart + FeatureFrameCount <= cache.frameCount; + frameStart += featureWindowStepFrames) + { + frameStarts.push_back(frameStart); + } + const size_t lastFrameStart = + cache.frameCount - FeatureFrameCount; + if (frameStarts.empty() || frameStarts.back() != lastFrameStart) + { + frameStarts.push_back(lastFrameStart); + } + + FusionState fusion; + const size_t requiredHits = + frameStarts.size() == 1u ? 1u : minConsecutiveHits; + + for (size_t i = 0u; i < frameStarts.size(); ++i) + { + const std::vector features = + BuildMfccWindow( + cache, + prepared, + frameStarts[i], + inputGain); + std::vector logits; + if (!run_embedded_model_logits(features, logits)) + { + continue; + } + UpdateFusion( + fusion, + logits, + smoothingAlpha, + confidenceThreshold, + marginThreshold, + requiredHits); + } + + std::cout + << "[INFO] ResBN INT8 KWS result: command=" + << keyword_command_to_string(fusion.best.command) + << ", confidence=" + << fusion.best.confidence + << ", windows=" + << frameStarts.size() + << ", stepFrames=" + << featureWindowStepFrames + << std::endl; + return fusion.best; + } + + bool ResBnKwsRecognizer::run_embedded_model_logits( + const std::vector& features, + std::vector& logits) const + { + if (features.size() != FeatureFrameCount * MfccBinCount) + { + return false; + } + + std::vector quantizedInput(features.size(), 0); + for (size_t i = 0u; i < features.size(); ++i) + { + quantizedInput[i] = QuantizeFloat( + features[i], + ResBnKwsModelData::ModelInput); + } + + std::vector layerA(ActivationElementCount, 0); + std::vector layerB(ActivationElementCount, 0); + std::vector layerC(ActivationElementCount, 0); + + Conv2DInt8( + quantizedInput.data(), + FeatureFrameCount, + MfccBinCount, + 1u, + ResBnKwsModelData::Stem, + ActivationChannels, + 10u, + 4u, + 2u, + 2u, + layerA.data(), + ActivationHeight, + ActivationWidth); + + for (size_t block = 0u; + block < ResBnKwsModelData::BlockCount; + ++block) + { + DepthwiseConv2DInt8( + layerA.data(), + ActivationHeight, + ActivationWidth, + ActivationChannels, + ResBnKwsModelData::Depthwise[block], + layerB.data()); + Conv2DInt8( + layerB.data(), + ActivationHeight, + ActivationWidth, + ActivationChannels, + ResBnKwsModelData::Pointwise[block], + ActivationChannels, + 1u, + 1u, + 1u, + 1u, + layerC.data(), + ActivationHeight, + ActivationWidth); + AddInt8( + layerA.data(), + layerC.data(), + ActivationElementCount, + ResBnKwsModelData::Adds[block], + layerB.data()); + layerA.swap(layerB); + } + + int8_t pooled[ActivationChannels] = {}; + int8_t quantizedLogits[ClassCount] = {}; + GlobalMeanInt8( + layerA.data(), + ActivationHeight, + ActivationWidth, + ActivationChannels, + pooled); + FullyConnectedInt8(pooled, quantizedLogits); + + logits.resize(ClassCount, 0.0f); + for (size_t i = 0u; i < ClassCount; ++i) + { + logits[i] = + (static_cast(quantizedLogits[i]) - + ResBnKwsModelData::ModelOutput.zeroPoint) * + ResBnKwsModelData::ModelOutput.scale; + } + return true; + } + + void ResBnKwsRecognizer::set_confidence_threshold(float threshold) + { + if (threshold >= 0.0f && threshold <= 1.0f) + { + confidenceThreshold = threshold; + } + } + + void ResBnKwsRecognizer::set_margin_threshold(float threshold) + { + if (threshold >= 0.0f && threshold <= 1.0f) + { + marginThreshold = threshold; + } + } + + void ResBnKwsRecognizer::set_smoothing_alpha(float alpha) + { + if (alpha >= 0.0f && alpha < 1.0f) + { + smoothingAlpha = alpha; + } + } + + void ResBnKwsRecognizer::set_min_consecutive_hits(size_t hits) + { + if (hits > 0u) + { + minConsecutiveHits = hits; + } + } + + void ResBnKwsRecognizer::set_feature_window_step_frames(size_t frames) + { + if (frames > 0u) + { + featureWindowStepFrames = frames; + } + } + + void ResBnKwsRecognizer::set_input_gain(float gain) + { + if (gain > 0.0f && gain <= 1.0f) + { + inputGain = gain; + } + } +} diff --git a/src/Apps/Game/src/recognition/ResBnKwsRecognizer.h b/src/Apps/Game/src/recognition/ResBnKwsRecognizer.h new file mode 100644 index 0000000..0d2c93e --- /dev/null +++ b/src/Apps/Game/src/recognition/ResBnKwsRecognizer.h @@ -0,0 +1,50 @@ +#pragma once + +#include "KeywordRecognizer.h" +#include +#include +#include + +namespace Game +{ + class ResBnKwsRecognizer : public IKeywordRecognizer + { + private: + float confidenceThreshold; + float marginThreshold; + float smoothingAlpha; + float inputGain; + size_t minConsecutiveHits; + size_t featureWindowStepFrames; + bool initialized; + + bool run_embedded_model_logits( + const std::vector& features, + std::vector& logits) const; + + public: + ResBnKwsRecognizer(); + explicit ResBnKwsRecognizer(const std::string& unusedModelPath); + ~ResBnKwsRecognizer(); + + bool init(); + KeywordRecognitionResult recognize( + const std::vector& samples, + uint32_t sampleRate, + uint32_t channels); + + void set_confidence_threshold(float threshold); + float get_confidence_threshold() const { return confidenceThreshold; } + void set_margin_threshold(float threshold); + float get_margin_threshold() const { return marginThreshold; } + void set_smoothing_alpha(float alpha); + float get_smoothing_alpha() const { return smoothingAlpha; } + void set_min_consecutive_hits(size_t hits); + size_t get_min_consecutive_hits() const { return minConsecutiveHits; } + void set_feature_window_step_frames(size_t frames); + size_t get_feature_window_step_frames() const { return featureWindowStepFrames; } + void set_input_gain(float gain) override; + float get_input_gain() const override { return inputGain; } + bool is_initialized() const { return initialized; } + }; +}