diff --git a/CHANGELOG.md b/CHANGELOG.md index 5690737b3d2fc392e4f4048b5a817ec8519d7dd6..24fd5d20f659dba08750f34de6113aafcb27240c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ This changelog aims to follow the guiding principles of - Add, subtract, multiply & absdiff enabled in OpenCV HAL. - MinMax enabled in OpenCV HAL, float version added. - Resize 4x4 for float. +- Resize 8x8 for float. - Resize 0.5x0.5 for uint8_t. - Conversion from float to (u)int8_t and vice versa. - KLEIDICV_LIMIT_SME2_TO_SELECTED_ALGORITHMS configuration option. diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 58f80cc5903240abc7361700573ccac0baff7cea..07a290df187dd7802d19e5ca9c962dbb58b33fd7 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -237,6 +237,11 @@ static void resize_linear_4x4_f32(benchmark::State& state) { } BENCHMARK(resize_linear_4x4_f32); +static void resize_linear_8x8_f32(benchmark::State& state) { + resize_upscale(kleidicv_resize_linear_f32, 8, 8, state); +} +BENCHMARK(resize_linear_8x8_f32); + template static void gaussian_blur(benchmark::State& state) { kleidicv_filter_context_t* context; diff --git a/conformity/opencv/test_resize.cpp b/conformity/opencv/test_resize.cpp index 966ccf922200224d85ec74146cf7460a70c6180d..1f6cbd6360083b8008bfa4a91e7e4da0466d4803 100644 --- a/conformity/opencv/test_resize.cpp +++ b/conformity/opencv/test_resize.cpp @@ -28,23 +28,29 @@ bool test_resize(int index, RecreatedMessageQueue& request_queue, for (size_t x = 5; x <= MaxSize; ++x) { for (size_t y = 5; y <= MaxSize; ++y) { cv::Mat input_mat(x, y, Format); - rng.fill(input_mat, cv::RNG::NORMAL, 0.0, 1.0e10); + if constexpr (CV_MAT_DEPTH(Format) == CV_32F) { + rng.fill(input_mat, cv::RNG::UNIFORM, 1, 1000000); + } else if constexpr (CV_MAT_DEPTH(Format) == CV_8U) { + rng.fill(input_mat, cv::RNG::UNIFORM, 0, 255); + } else { + return true; + } cv::Mat actual_mat = exec_resize(input_mat); cv::Mat expected_mat = get_expected_from_subordinate( index, request_queue, reply_queue, input_mat); bool success = (CV_MAT_DEPTH(Format) == CV_32F && - !are_float_matrices_different(1e-5, actual_mat, + !are_float_matrices_different(0.01F, actual_mat, expected_mat)) || (CV_MAT_DEPTH(Format) == CV_8U && - !are_matrices_different(0, actual_mat, expected_mat)); + !are_matrices_different(1, actual_mat, expected_mat)); if (!success) { fail_print_matrices(x, y, input_mat, actual_mat, expected_mat); + return true; } } } - return false; } #endif @@ -52,13 +58,14 @@ bool test_resize(int index, RecreatedMessageQueue& request_queue, std::vector& resize_tests_get() { // clang-format off static std::vector tests = { - TEST("Resize4x4 float32, INTER_LINEAR", (test_resize<4000, CV_HAL_INTER_LINEAR, 16, CV_32FC4>), (exec_resize<4000, CV_HAL_INTER_LINEAR>)), - TEST("Resize2x2 float32, INTER_LINEAR", (test_resize<2000, CV_HAL_INTER_LINEAR, 16, CV_32FC4>), (exec_resize<2000, CV_HAL_INTER_LINEAR>)), + TEST("Resize2x2 float32, INTER_LINEAR", (test_resize<2000, CV_HAL_INTER_LINEAR, 16, CV_32FC1>), (exec_resize<2000, CV_HAL_INTER_LINEAR>)), + TEST("Resize4x4 float32, INTER_LINEAR", (test_resize<4000, CV_HAL_INTER_LINEAR, 16, CV_32FC1>), (exec_resize<4000, CV_HAL_INTER_LINEAR>)), + TEST("Resize8x8 float32, INTER_LINEAR", (test_resize<8000, CV_HAL_INTER_LINEAR, 16, CV_32FC1>), (exec_resize<8000, CV_HAL_INTER_LINEAR>)), - TEST("Resize0.5x0.5 uint8, INTER_AREA", (test_resize<500, CV_HAL_INTER_AREA, 32, CV_8UC4>), (exec_resize<500, CV_HAL_INTER_AREA>)), - TEST("Resize0.5x0.5 uint8, INTER_LINEAR", (test_resize<500, CV_HAL_INTER_LINEAR, 32, CV_8UC4>), (exec_resize<500, CV_HAL_INTER_LINEAR>)), - TEST("Resize2x2 uint8, INTER_LINEAR", (test_resize<2000, CV_HAL_INTER_LINEAR, 16, CV_8UC4>), (exec_resize<2000, CV_HAL_INTER_LINEAR>)), - TEST("Resize4x4 uint8, INTER_LINEAR", (test_resize<4000, CV_HAL_INTER_LINEAR, 16, CV_8UC4>), (exec_resize<4000, CV_HAL_INTER_LINEAR>)), + TEST("Resize0.5x0.5 uint8, INTER_AREA", (test_resize<500, CV_HAL_INTER_AREA, 32, CV_8UC1>), (exec_resize<500, CV_HAL_INTER_AREA>)), + TEST("Resize0.5x0.5 uint8, INTER_LINEAR", (test_resize<500, CV_HAL_INTER_LINEAR, 32, CV_8UC1>), (exec_resize<500, CV_HAL_INTER_LINEAR>)), + TEST("Resize2x2 uint8, INTER_LINEAR", (test_resize<2000, CV_HAL_INTER_LINEAR, 16, CV_8UC1>), (exec_resize<2000, CV_HAL_INTER_LINEAR>)), + TEST("Resize4x4 uint8, INTER_LINEAR", (test_resize<4000, CV_HAL_INTER_LINEAR, 16, CV_8UC1>), (exec_resize<4000, CV_HAL_INTER_LINEAR>)), }; // clang-format on return tests; diff --git a/conformity/opencv/tests.h b/conformity/opencv/tests.h index cce5aefc46873029b6984591c514c6bdc2e0aea4..7300bedad5856fb879f0c0bfa01493ccba428ed4 100644 --- a/conformity/opencv/tests.h +++ b/conformity/opencv/tests.h @@ -40,6 +40,8 @@ bool are_float_matrices_different(T threshold_percent, cv::Mat& exp, T diff_percentage = (diff / std::abs(exp.at(i, j))) * 100; if (diff_percentage > threshold_percent) { std::cout << "=== Mismatch at: " << i << " " << j << std::endl + << "Expected: " << exp.at(i, j) + << " Actual: " << act.at(i, j) << std::endl << "Relative diff: " << diff_percentage << std::endl << std::endl; return true; diff --git a/doc/functionality.md b/doc/functionality.md index 57541bf422491bc65eabcc70708ca6942e6d37cb..53cfc9f9128a3302396e9ec95ae0206f64bc9e0e 100644 --- a/doc/functionality.md +++ b/doc/functionality.md @@ -88,3 +88,4 @@ See `doc/opencv.md` for details of the functionality available in OpenCV. |-------------|-----|-----| | 2x2 | x | x | | 4x4 | x | x | +| 8x8 | | x | diff --git a/doc/opencv.md b/doc/opencv.md index d9219c17250d6834bf8f1b7814f4d8fca577f8f8..3e801b6def8af91452c119955e19060af181de40 100644 --- a/doc/opencv.md +++ b/doc/opencv.md @@ -145,8 +145,8 @@ Release context set up by [`morphology_init`](#morphology_init). ### `resize` Notes on parameters: * In-place operation not supported. -* `src_type` - only supports `CV_8UC1` or `CV_32FC1`, relative sizes can be 0.5x0.5 (`CV_8UC1` only), 2x2 and 4x4. -* `dst_width`,`dst_height` - must both be the same multiple of `src_width` and `src_height` respectively, and that multiple must be either 0.5, 2 or 4. +* `src_type` - only supports `CV_8UC1` or `CV_32FC1`, relative sizes can be 0.5x0.5 (`CV_8UC1` only), 2x2, 4x4 and 8x8 (`CV_32FC1` only). +* `dst_width`,`dst_height` - must both be the same multiple of `src_width` and `src_height` respectively, and that multiple must be either 0.5, 2, 4 or 8. * `inv_scale_x`,`inv_scale_y` - must be 0 or `dst_width / src_width`. * `interpolation` - Must be `INTER_LINEAR` or `INTER_AREA` (0.5 by 0.5 only). diff --git a/kleidicv/include/kleidicv/kleidicv.h b/kleidicv/include/kleidicv/kleidicv.h index 06be5ca8f959333f682b8a53604310923d086421..698b9286f22979f691289cc2519d38f365c7a954 100644 --- a/kleidicv/include/kleidicv/kleidicv.h +++ b/kleidicv/include/kleidicv/kleidicv.h @@ -1014,7 +1014,7 @@ KLEIDICV_API_DECLARATION(kleidicv_resize_to_quarter_u8, const uint8_t *src, /// Resize image using linear interpolation. /// -/// At present only 2*2 and 4*4 upsizing is supported. +/// At present only 2*2 and 4*4 upsizing is supported, and 8x8 for float data. /// For other ratios KLEIDICV_ERROR_NOT_IMPLEMENTED /// will be returned. /// The total number of pixels in the destination is limited to diff --git a/kleidicv/src/resize/resize_linear_neon.cpp b/kleidicv/src/resize/resize_linear_neon.cpp index 5f216d3a1259ec9381a7f3a3fc5fe8b87dbbd101..5f0d01852d3caf6a23d70d1fe196557f217bc02e 100644 --- a/kleidicv/src/resize/resize_linear_neon.cpp +++ b/kleidicv/src/resize/resize_linear_neon.cpp @@ -734,6 +734,191 @@ KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_4x4_f32( return KLEIDICV_OK; } +KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_8x8_f32( + const float *src, size_t src_stride, size_t src_width, size_t src_height, + float *dst, size_t dst_stride) { + size_t dst_width = src_width * 8; + size_t dst_height = src_height * 8; + src_stride /= sizeof(float); + dst_stride /= sizeof(float); + + float coeffs_a[] = {15 / 16.0, 13 / 16.0, 11 / 16.0, 9 / 16.0, + 7 / 16.0, 5 / 16.0, 3 / 16.0, 1 / 16.0}; + float coeffs_b[] = {1 / 16.0, 3 / 16.0, 5 / 16.0, 7 / 16.0, + 9 / 16.0, 11 / 16.0, 13 / 16.0, 15 / 16.0}; + float32x4_t coeffs_a0 = vld1q_f32(&coeffs_a[0]); + float32x4_t coeffs_a1 = vld1q_f32(&coeffs_a[4]); + float32x4_t coeffs_b0 = vld1q_f32(&coeffs_b[0]); + float32x4_t coeffs_b1 = vld1q_f32(&coeffs_b[4]); + + auto lerp1d_vector_n = [](float p, float32x4_t a, float q, float32x4_t b) { + return vmlaq_n_f32(vmulq_n_f32(a, p), b, q); + }; + + auto lerp1d_vector = [](float32x4_t p, float32x4_t a, float32x4_t q, + float32x4_t b) { + return vmlaq_f32(vmulq_f32(a, p), b, q); + }; + + // Handle top or bottom edge + auto process_edge_row = + [src_width, lerp1d_vector, &coeffs_a0, &coeffs_a1, &coeffs_b0, + &coeffs_b1](const float *src_row, float *dst_row, size_t dst_stride) { + float32x4_t a, b = vdupq_n_f32(src_row[0]); + for (size_t src_x = 0; src_x + 1 < src_width; src_x++) { + a = b; + b = vdupq_n_f32(src_row[src_x + 1]); + float *dst_row0 = dst_row + src_x * 8 + 4; + float *dst_row1 = dst_row0 + dst_stride; + float *dst_row2 = dst_row1 + dst_stride; + float *dst_row3 = dst_row2 + dst_stride; + float32x4_t dst = lerp1d_vector(coeffs_a0, a, coeffs_b0, b); + vst1q(dst_row0, dst); + vst1q(dst_row1, dst); + vst1q(dst_row2, dst); + vst1q(dst_row3, dst); + dst = lerp1d_vector(coeffs_a1, a, coeffs_b1, b); + vst1q(dst_row0 + 4, dst); + vst1q(dst_row1 + 4, dst); + vst1q(dst_row2 + 4, dst); + vst1q(dst_row3 + 4, dst); + } + }; + + float32x4_t coeffs_p0 = vmulq_n_f32(coeffs_a0, 15.0 / 16); + float32x4_t coeffs_q0 = vmulq_n_f32(coeffs_b0, 15.0 / 16); + float32x4_t coeffs_r0 = vmulq_n_f32(coeffs_a0, 1.0 / 16); + float32x4_t coeffs_s0 = vmulq_n_f32(coeffs_b0, 1.0 / 16); + float32x4_t coeffs_p1 = vmulq_n_f32(coeffs_a1, 15.0 / 16); + float32x4_t coeffs_q1 = vmulq_n_f32(coeffs_b1, 15.0 / 16); + float32x4_t coeffs_r1 = vmulq_n_f32(coeffs_a1, 1.0 / 16); + float32x4_t coeffs_s1 = vmulq_n_f32(coeffs_b1, 1.0 / 16); + + auto lerp2d_vector = [](float32x4_t a, float32x4_t p, float32x4_t b, + float32x4_t q, float32x4_t c, float32x4_t r, + float32x4_t d, float32x4_t s) { + return vmlaq_f32(vmlaq_f32(vmlaq_f32(vmulq_f32(a, p), b, q), c, r), d, s); + }; + + auto process_row = [src_width, lerp2d_vector, lerp1d_vector_n, &coeffs_p0, + &coeffs_q0, &coeffs_r0, &coeffs_s0, &coeffs_p1, + &coeffs_q1, &coeffs_r1, + &coeffs_s1](const float *src_row0, const float *src_row1, + float *dst_row0, size_t dst_stride) { + // Middle elements + dst_row0 += 4; + float *dst_row1 = dst_row0 + dst_stride; + float *dst_row2 = dst_row1 + dst_stride; + float *dst_row3 = dst_row2 + dst_stride; + float *dst_row4 = dst_row3 + dst_stride; + float *dst_row5 = dst_row4 + dst_stride; + float *dst_row6 = dst_row5 + dst_stride; + float *dst_row7 = dst_row6 + dst_stride; + float32x4_t a, b = vdupq_n_f32(src_row0[0]); + float32x4_t c, d = vdupq_n_f32(src_row1[0]); + for (size_t src_x = 0; src_x + 1 < src_width; src_x++) { + a = b; + b = vdupq_n_f32(src_row0[src_x + 1]); + c = d; + d = vdupq_n_f32(src_row1[src_x + 1]); + float32x4_t dst_0 = + lerp2d_vector(coeffs_p0, a, coeffs_q0, b, coeffs_r0, c, coeffs_s0, d); + vst1q(dst_row0, dst_0); + float32x4_t dst_7 = + lerp2d_vector(coeffs_r0, a, coeffs_s0, b, coeffs_p0, c, coeffs_q0, d); + vst1q(dst_row7, dst_7); + vst1q(dst_row1, lerp1d_vector_n(6.0 / 7, dst_0, 1.0 / 7, dst_7)); + vst1q(dst_row2, lerp1d_vector_n(5.0 / 7, dst_0, 2.0 / 7, dst_7)); + vst1q(dst_row3, lerp1d_vector_n(4.0 / 7, dst_0, 3.0 / 7, dst_7)); + vst1q(dst_row4, lerp1d_vector_n(3.0 / 7, dst_0, 4.0 / 7, dst_7)); + vst1q(dst_row5, lerp1d_vector_n(2.0 / 7, dst_0, 5.0 / 7, dst_7)); + vst1q(dst_row6, lerp1d_vector_n(1.0 / 7, dst_0, 6.0 / 7, dst_7)); + dst_row0 += 4; + dst_row1 += 4; + dst_row2 += 4; + dst_row3 += 4; + dst_row4 += 4; + dst_row5 += 4; + dst_row6 += 4; + dst_row7 += 4; + dst_0 = + lerp2d_vector(coeffs_p1, a, coeffs_q1, b, coeffs_r1, c, coeffs_s1, d); + vst1q(dst_row0, dst_0); + dst_7 = + lerp2d_vector(coeffs_r1, a, coeffs_s1, b, coeffs_p1, c, coeffs_q1, d); + vst1q(dst_row7, dst_7); + vst1q(dst_row1, lerp1d_vector_n(6.0 / 7, dst_0, 1.0 / 7, dst_7)); + vst1q(dst_row2, lerp1d_vector_n(5.0 / 7, dst_0, 2.0 / 7, dst_7)); + vst1q(dst_row3, lerp1d_vector_n(4.0 / 7, dst_0, 3.0 / 7, dst_7)); + vst1q(dst_row4, lerp1d_vector_n(3.0 / 7, dst_0, 4.0 / 7, dst_7)); + vst1q(dst_row5, lerp1d_vector_n(2.0 / 7, dst_0, 5.0 / 7, dst_7)); + vst1q(dst_row6, lerp1d_vector_n(1.0 / 7, dst_0, 6.0 / 7, dst_7)); + dst_row0 += 4; + dst_row1 += 4; + dst_row2 += 4; + dst_row3 += 4; + dst_row4 += 4; + dst_row5 += 4; + dst_row6 += 4; + dst_row7 += 4; + } + }; + + // Corners + auto set_corner = [dst, dst_stride](size_t left_column, size_t top_row, + float value) { + float *row = dst + dst_stride * top_row + left_column; + for (size_t i = 0; i < 4; ++i) { + for (size_t j = 0; j < 4; ++j) { + row[j] = value; + } + row += dst_stride; + } + }; + set_corner(0, 0, src[0]); + set_corner(dst_width - 4, 0, src[src_width - 1]); + set_corner(0, dst_height - 4, src[src_stride * (src_height - 1)]); + set_corner(dst_width - 4, dst_height - 4, + src[src_stride * (src_height - 1) + src_width - 1]); + + // Left & right edge + for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { + float *dst_row = dst + dst_stride * (src_y * 8 + 4); + const float *src_row0 = src + src_stride * src_y; + const float *src_row1 = src_row0 + src_stride; + const float s0l = src_row0[0], s1l = src_row1[0]; + const float s0r = src_row0[src_width - 1], s1r = src_row1[src_width - 1]; + for (size_t i = 0; i < 8; ++i) { + vst1q(dst_row, lerp1d_vector_n(static_cast(15 - i * 2) / 16.0F, + vdupq_n_f32(s0l), + static_cast(i * 2 + 1) / 16.0F, + vdupq_n_f32(s1l))); + vst1q(dst_row + dst_width - 4, + lerp1d_vector_n( + static_cast(15 - i * 2) / 16.0F, vdupq_n_f32(s0r), + static_cast(i * 2 + 1) / 16.0F, vdupq_n_f32(s1r))); + dst_row += dst_stride; + } + } + + // Top rows + process_edge_row(src, dst, dst_stride); + + // Middle rows + for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { + size_t dst_y = src_y * 8 + 4; + const float *src_row0 = src + src_stride * src_y; + const float *src_row1 = src_row0 + src_stride; + process_row(src_row0, src_row1, dst + dst_stride * dst_y, dst_stride); + } + + // Bottom rows + process_edge_row(src + src_stride * (src_height - 1), + dst + dst_stride * (dst_height - 4), dst_stride); + + return KLEIDICV_OK; +} + KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t resize_linear_f32(const float *src, size_t src_stride, size_t src_width, size_t src_height, @@ -754,6 +939,10 @@ kleidicv_error_t resize_linear_f32(const float *src, size_t src_stride, return resize_4x4_f32(src, src_stride, src_width, src_height, dst, dst_stride); } + if (src_width * 8 == dst_width && src_height * 8 == dst_height) { + return resize_8x8_f32(src, src_stride, src_width, src_height, dst, + dst_stride); + } return KLEIDICV_ERROR_NOT_IMPLEMENTED; } diff --git a/kleidicv/src/resize/resize_linear_sc.h b/kleidicv/src/resize/resize_linear_sc.h index 811ca965aed18340e8013d9cd1bb3a5a4e4e3ed7..c43b1e497875c44160e0f149c63fd4355d51277e 100644 --- a/kleidicv/src/resize/resize_linear_sc.h +++ b/kleidicv/src/resize/resize_linear_sc.h @@ -5,6 +5,8 @@ #ifndef KLEIDICV_RESIZE_LINEAR_SC_H #define KLEIDICV_RESIZE_LINEAR_SC_H +#include + #include "kleidicv/kleidicv.h" #include "kleidicv/sve2.h" @@ -638,6 +640,488 @@ KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_4x4_f32_sc( return KLEIDICV_OK; } +KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_8x8_f32_sve128_sc( + const float *src, size_t src_stride, size_t src_width, size_t src_height, + float *dst, size_t dst_stride) KLEIDICV_STREAMING_COMPATIBLE { + size_t dst_width = src_width * 8; + size_t dst_height = src_height * 8; + src_stride /= sizeof(float); + dst_stride /= sizeof(float); + + float coeffs_a[] = {15 / 16.0, 13 / 16.0, 11 / 16.0, 9 / 16.0, + 7 / 16.0, 5 / 16.0, 3 / 16.0, 1 / 16.0}; + float coeffs_b[] = {1 / 16.0, 3 / 16.0, 5 / 16.0, 7 / 16.0, + 9 / 16.0, 11 / 16.0, 13 / 16.0, 15 / 16.0}; + svfloat32_t coeffs_a0 = svld1(svptrue_b32(), &coeffs_a[0]); + svfloat32_t coeffs_a1 = svld1(svptrue_b32(), &coeffs_a[4]); + svfloat32_t coeffs_b0 = svld1(svptrue_b32(), &coeffs_b[0]); + svfloat32_t coeffs_b1 = svld1(svptrue_b32(), &coeffs_b[4]); + + auto lerp1d_vector_n = [](svbool_t pg, float p, svfloat32_t a, float q, + svfloat32_t b) { + return svmla_n_f32_x(pg, svmul_n_f32_x(pg, a, p), b, q); + }; + + auto lerp1d_vector = [](svbool_t pg, svfloat32_t p, svfloat32_t a, + svfloat32_t q, svfloat32_t b) { + return svmla_f32_x(pg, svmul_f32_x(pg, a, p), b, q); + }; + + // Handle top or bottom edge + auto process_edge_row = + [src_width, lerp1d_vector, &coeffs_a0, &coeffs_a1, &coeffs_b0, + &coeffs_b1](const float *src_row, float *dst_row, size_t dst_stride) { + svfloat32_t a, b = svdup_n_f32(src_row[0]); + for (size_t src_x = 0; src_x + 1 < src_width; src_x++) { + a = b; + b = svdup_n_f32(src_row[src_x + 1]); + float *dst_row0 = dst_row + src_x * 8 + 4; + float *dst_row1 = dst_row0 + dst_stride; + float *dst_row2 = dst_row1 + dst_stride; + float *dst_row3 = dst_row2 + dst_stride; + svfloat32_t dst = + lerp1d_vector(svptrue_b32(), coeffs_a0, a, coeffs_b0, b); + svst1(svptrue_b32(), dst_row0, dst); + svst1(svptrue_b32(), dst_row1, dst); + svst1(svptrue_b32(), dst_row2, dst); + svst1(svptrue_b32(), dst_row3, dst); + dst = lerp1d_vector(svptrue_b32(), coeffs_a1, a, coeffs_b1, b); + svst1(svptrue_b32(), dst_row0 + 4, dst); + svst1(svptrue_b32(), dst_row1 + 4, dst); + svst1(svptrue_b32(), dst_row2 + 4, dst); + svst1(svptrue_b32(), dst_row3 + 4, dst); + } + }; + + svfloat32_t coeffs_p0 = svmul_n_f32_x(svptrue_b32(), coeffs_a0, 15.0 / 16); + svfloat32_t coeffs_q0 = svmul_n_f32_x(svptrue_b32(), coeffs_b0, 15.0 / 16); + svfloat32_t coeffs_r0 = svmul_n_f32_x(svptrue_b32(), coeffs_a0, 1.0 / 16); + svfloat32_t coeffs_s0 = svmul_n_f32_x(svptrue_b32(), coeffs_b0, 1.0 / 16); + svfloat32_t coeffs_p1 = svmul_n_f32_x(svptrue_b32(), coeffs_a1, 15.0 / 16); + svfloat32_t coeffs_q1 = svmul_n_f32_x(svptrue_b32(), coeffs_b1, 15.0 / 16); + svfloat32_t coeffs_r1 = svmul_n_f32_x(svptrue_b32(), coeffs_a1, 1.0 / 16); + svfloat32_t coeffs_s1 = svmul_n_f32_x(svptrue_b32(), coeffs_b1, 1.0 / 16); + + auto lerp2d_vector = [](svbool_t pg, svfloat32_t a, svfloat32_t p, + svfloat32_t b, svfloat32_t q, svfloat32_t c, + svfloat32_t r, svfloat32_t d, svfloat32_t s) { + return svmla_f32_x( + pg, svmla_f32_x(pg, svmla_f32_x(pg, svmul_f32_x(pg, a, p), b, q), c, r), + d, s); + }; + + auto process_row = [src_width, lerp2d_vector, lerp1d_vector_n, &coeffs_p0, + &coeffs_q0, &coeffs_r0, &coeffs_s0, &coeffs_p1, + &coeffs_q1, &coeffs_r1, &coeffs_s1]( + const float *src_row0, const float *src_row1, + float *dst_row0, + size_t dst_stride) KLEIDICV_STREAMING_COMPATIBLE { + // Middle elements + dst_row0 += 4; + float *dst_row1 = dst_row0 + dst_stride; + float *dst_row2 = dst_row1 + dst_stride; + float *dst_row3 = dst_row2 + dst_stride; + float *dst_row4 = dst_row3 + dst_stride; + float *dst_row5 = dst_row4 + dst_stride; + float *dst_row6 = dst_row5 + dst_stride; + float *dst_row7 = dst_row6 + dst_stride; + svfloat32_t a, b = svdup_n_f32(src_row0[0]); + svfloat32_t c, d = svdup_n_f32(src_row1[0]); + for (size_t src_x = 0; src_x + 1 < src_width; src_x++) { + a = b; + b = svdup_n_f32(src_row0[src_x + 1]); + c = d; + d = svdup_n_f32(src_row1[src_x + 1]); + svfloat32_t dst_0 = lerp2d_vector(svptrue_b32(), coeffs_p0, a, coeffs_q0, + b, coeffs_r0, c, coeffs_s0, d); + svst1(svptrue_b32(), dst_row0, dst_0); + svfloat32_t dst_7 = lerp2d_vector(svptrue_b32(), coeffs_r0, a, coeffs_s0, + b, coeffs_p0, c, coeffs_q0, d); + svst1(svptrue_b32(), dst_row7, dst_7); + svst1(svptrue_b32(), dst_row1, + lerp1d_vector_n(svptrue_b32(), 6.0 / 7, dst_0, 1.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row2, + lerp1d_vector_n(svptrue_b32(), 5.0 / 7, dst_0, 2.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row3, + lerp1d_vector_n(svptrue_b32(), 4.0 / 7, dst_0, 3.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row4, + lerp1d_vector_n(svptrue_b32(), 3.0 / 7, dst_0, 4.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row5, + lerp1d_vector_n(svptrue_b32(), 2.0 / 7, dst_0, 5.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row6, + lerp1d_vector_n(svptrue_b32(), 1.0 / 7, dst_0, 6.0 / 7, dst_7)); + dst_row0 += 4; + dst_row1 += 4; + dst_row2 += 4; + dst_row3 += 4; + dst_row4 += 4; + dst_row5 += 4; + dst_row6 += 4; + dst_row7 += 4; + dst_0 = lerp2d_vector(svptrue_b32(), coeffs_p1, a, coeffs_q1, b, + coeffs_r1, c, coeffs_s1, d); + svst1(svptrue_b32(), dst_row0, dst_0); + dst_7 = lerp2d_vector(svptrue_b32(), coeffs_r1, a, coeffs_s1, b, + coeffs_p1, c, coeffs_q1, d); + svst1(svptrue_b32(), dst_row7, dst_7); + svst1(svptrue_b32(), dst_row1, + lerp1d_vector_n(svptrue_b32(), 6.0 / 7, dst_0, 1.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row2, + lerp1d_vector_n(svptrue_b32(), 5.0 / 7, dst_0, 2.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row3, + lerp1d_vector_n(svptrue_b32(), 4.0 / 7, dst_0, 3.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row4, + lerp1d_vector_n(svptrue_b32(), 3.0 / 7, dst_0, 4.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row5, + lerp1d_vector_n(svptrue_b32(), 2.0 / 7, dst_0, 5.0 / 7, dst_7)); + svst1(svptrue_b32(), dst_row6, + lerp1d_vector_n(svptrue_b32(), 1.0 / 7, dst_0, 6.0 / 7, dst_7)); + dst_row0 += 4; + dst_row1 += 4; + dst_row2 += 4; + dst_row3 += 4; + dst_row4 += 4; + dst_row5 += 4; + dst_row6 += 4; + dst_row7 += 4; + } + }; + + // Corners + auto set_corner = [dst, dst_stride](size_t left_column, size_t top_row, + float value) { + float *row = dst + dst_stride * top_row + left_column; + for (size_t i = 0; i < 4; ++i) { + for (size_t j = 0; j < 4; ++j) { + row[j] = value; + } + row += dst_stride; + } + }; + set_corner(0, 0, src[0]); + set_corner(dst_width - 4, 0, src[src_width - 1]); + set_corner(0, dst_height - 4, src[src_stride * (src_height - 1)]); + set_corner(dst_width - 4, dst_height - 4, + src[src_stride * (src_height - 1) + src_width - 1]); + + // Left & right edge + for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { + float *dst_row = dst + dst_stride * (src_y * 8 + 4); + const float *src_row0 = src + src_stride * src_y; + const float *src_row1 = src_row0 + src_stride; + const float s0l = src_row0[0], s1l = src_row1[0]; + const float s0r = src_row0[src_width - 1], s1r = src_row1[src_width - 1]; + for (size_t i = 0; i < 8; ++i) { + svst1( + svptrue_b32(), dst_row, + lerp1d_vector_n(svptrue_b32(), static_cast(15 - i * 2) / 16.0F, + svdup_f32(s0l), static_cast(i * 2 + 1) / 16.0F, + svdup_f32(s1l))); + svst1( + svptrue_b32(), dst_row + dst_width - 4, + lerp1d_vector_n(svptrue_b32(), static_cast(15 - i * 2) / 16.0F, + svdup_f32(s0r), static_cast(i * 2 + 1) / 16.0F, + svdup_f32(s1r))); + dst_row += dst_stride; + } + } + + // Top rows + process_edge_row(src, dst, dst_stride); + + // Middle rows + for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { + size_t dst_y = src_y * 8 + 4; + const float *src_row0 = src + src_stride * src_y; + const float *src_row1 = src_row0 + src_stride; + process_row(src_row0, src_row1, dst + dst_stride * dst_y, dst_stride); + } + + // Bottom rows + process_edge_row(src + src_stride * (src_height - 1), + dst + dst_stride * (dst_height - 4), dst_stride); + + return KLEIDICV_OK; +} + +KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_8x8_f32_sve256plus_sc( + const float *src, size_t src_stride, size_t src_width, size_t src_height, + float *dst, size_t dst_stride) KLEIDICV_STREAMING_COMPATIBLE { + size_t dst_width = src_width * 8; + size_t dst_height = src_height * 8; + src_stride /= sizeof(float); + dst_stride /= sizeof(float); + + svuint32_t indices_0a, indices_0b, indices_1a, indices_1b, indices_2a, + indices_2b, indices_3a, indices_3b; + { + // indices for row 0 + svuint32_t tmp_2x = svreinterpret_u32_u64(svindex_u64(0, 0x100000001UL)); + svuint32_t tmp_4x = svzip1(tmp_2x, tmp_2x); // 0, 0, 0, 0, 1, 1, 1, 1, ... + indices_0a = svzip1(tmp_4x, tmp_4x); // 8 times 0, then 8 times 1, ... + indices_1a = svzip2(tmp_4x, tmp_4x); + // next section, e.g. in case of 512-bit regs (=16 x F32), it is 4, 4, 4, 4, + // 5, 5, 5, 5, ... + tmp_4x = svzip2(tmp_2x, tmp_2x); + indices_2a = svzip1(tmp_4x, tmp_4x); + indices_3a = svzip2(tmp_4x, tmp_4x); + + // same as above, just all numbers are bigger by one (for row 1) + tmp_2x = svreinterpret_u32_u64(svindex_u64(0x100000001UL, 0x100000001UL)); + tmp_4x = svzip1(tmp_2x, tmp_2x); // 1, 1, 1, 1, ... + indices_0b = svzip1(tmp_4x, tmp_4x); // 8 times 1, then 8 times 2, ... + indices_1b = svzip2(tmp_4x, tmp_4x); + // next section, e.g. in case of 512-bit regs (=16 x F32), it is 5, 5, 5, 5, + // 6, 6, 6, 6, ... + tmp_4x = svzip2(tmp_2x, tmp_2x); + indices_2b = svzip1(tmp_4x, tmp_4x); + indices_3b = svzip2(tmp_4x, tmp_4x); + } + + svfloat32_t coeffs_a, coeffs_b; + { + // Prepare 1/16, 3/16, 5/16, ..., 15/16, repeated + svuint32_t linear = svindex_u32(1, 2); + svfloat32_t repetitive_float = // mod 16 + svcvt_f32_x(svptrue_b32(), svand_n_u32_m(svptrue_b32(), linear, 0x0F)); + coeffs_b = svdiv_n_f32_x(svptrue_b32(), repetitive_float, 16.0F); + coeffs_a = svsub_x(svptrue_b32(), svdup_f32(1.0F), coeffs_b); + } + auto lerp1d_vector = + [](svbool_t pg, float p, svfloat32_t a, float q, svfloat32_t b) + KSC { return svmla_n_f32_x(pg, svmul_n_f32_x(pg, a, p), b, q); }; + + auto index_and_lerp1d = [&coeffs_a, &coeffs_b]( + svbool_t pg, svuint32_t indices_a, + svuint32_t indices_b, svfloat32_t src) KSC { + return svmla_f32_x(pg, svmul_f32_x(pg, svtbl(src, indices_a), coeffs_a), + svtbl(src, indices_b), coeffs_b); + }; + + // Handle top or bottom edge + auto process_edge_row = [src_width, index_and_lerp1d, &indices_0a, + &indices_0b, &indices_1a, &indices_1b, &indices_2a, + &indices_2b, &indices_3a, + &indices_3b](const float *src_row, float *dst_row, + size_t dst_stride) KSC { + for (size_t src_x = 0; src_x + 1 < src_width; src_x += svcntw() / 2) { + svbool_t pg = svwhilelt_b32(src_x, src_width); + svfloat32_t svsrc = svld1_f32(pg, src_row + src_x); + + size_t dst_length = 8 * (src_width - src_x - 1); + svbool_t pg_1 = svwhilelt_b32(0UL, dst_length); + svbool_t pg_2 = svwhilelt_b32(svcntw(), dst_length); + svbool_t pg_3 = svwhilelt_b32(2 * svcntw(), dst_length); + svbool_t pg_4 = svwhilelt_b32(3 * svcntw(), dst_length); + + float *dst_row0 = dst_row + src_x * 8 + 4; + float *dst_row1 = dst_row0 + dst_stride; + float *dst_row2 = dst_row1 + dst_stride; + float *dst_row3 = dst_row2 + dst_stride; + svfloat32_t dst = index_and_lerp1d(pg_1, indices_0a, indices_0b, svsrc); + svst1(pg_1, dst_row0, dst); + svst1(pg_1, dst_row1, dst); + svst1(pg_1, dst_row2, dst); + svst1(pg_1, dst_row3, dst); + + dst = index_and_lerp1d(pg_2, indices_1a, indices_1b, svsrc); + svst1_vnum(pg_2, dst_row0, 1, dst); + svst1_vnum(pg_2, dst_row1, 1, dst); + svst1_vnum(pg_2, dst_row2, 1, dst); + svst1_vnum(pg_2, dst_row3, 1, dst); + + dst = index_and_lerp1d(pg_3, indices_2a, indices_2b, svsrc); + svst1_vnum(pg_3, dst_row0, 2, dst); + svst1_vnum(pg_3, dst_row1, 2, dst); + svst1_vnum(pg_3, dst_row2, 2, dst); + svst1_vnum(pg_3, dst_row3, 2, dst); + + dst = index_and_lerp1d(pg_4, indices_3a, indices_3b, svsrc); + svst1_vnum(pg_4, dst_row0, 3, dst); + svst1_vnum(pg_4, dst_row1, 3, dst); + svst1_vnum(pg_4, dst_row2, 3, dst); + svst1_vnum(pg_4, dst_row3, 3, dst); + } + }; + + svfloat32_t coeffs_p = svmul_n_f32_x(svptrue_b32(), coeffs_a, 15.0 / 16); + svfloat32_t coeffs_q = svmul_n_f32_x(svptrue_b32(), coeffs_b, 15.0 / 16); + svfloat32_t coeffs_r = svmul_n_f32_x(svptrue_b32(), coeffs_a, 1.0 / 16); + svfloat32_t coeffs_s = svmul_n_f32_x(svptrue_b32(), coeffs_b, 1.0 / 16); + + auto index_and_lerp2d = [&coeffs_p, &coeffs_q, &coeffs_r, &coeffs_s]( + svbool_t pg, svuint32_t indices_a, + svuint32_t indices_b, svfloat32_t src0, + svfloat32_t src1) KSC { + return svmla_f32_x( + pg, + svmla_f32_x( + pg, + svmla_f32_x(pg, svmul_f32_x(pg, svtbl(src0, indices_a), coeffs_p), + svtbl(src0, indices_b), coeffs_q), + svtbl(src1, indices_a), coeffs_r), + svtbl(src1, indices_b), coeffs_s); + }; + + auto process_row = [src_width, index_and_lerp2d, lerp1d_vector, &indices_0a, + &indices_0b, &indices_1a, &indices_1b, &indices_2a, + &indices_2b, &indices_3a, &indices_3b]( + const float *src_row0, const float *src_row1, + float *dst_row, + size_t dst_stride) KLEIDICV_STREAMING_COMPATIBLE { + // Middle elements + for (size_t src_x = 0; src_x + 1 < src_width; src_x += svcntw() / 2) { + size_t dst_x = src_x * 8 + 4; + + svbool_t pg = svwhilelt_b32(src_x, src_width); + svfloat32_t src_0 = svld1_f32(pg, src_row0 + src_x); + svfloat32_t src_1 = svld1_f32(pg, src_row1 + src_x); + + size_t dst_length = 8 * (src_width - src_x - 1); + svbool_t pg_1 = svwhilelt_b32(0UL, dst_length); + svbool_t pg_2 = svwhilelt_b32(svcntw(), dst_length); + svbool_t pg_3 = svwhilelt_b32(2 * svcntw(), dst_length); + svbool_t pg_4 = svwhilelt_b32(3 * svcntw(), dst_length); + + float *dst_row0 = dst_row + dst_x; + float *dst_row1 = dst_row0 + dst_stride; + float *dst_row2 = dst_row1 + dst_stride; + float *dst_row3 = dst_row2 + dst_stride; + float *dst_row4 = dst_row3 + dst_stride; + float *dst_row5 = dst_row4 + dst_stride; + float *dst_row6 = dst_row5 + dst_stride; + float *dst_row7 = dst_row6 + dst_stride; + + svfloat32_t dst_0 = + index_and_lerp2d(pg_1, indices_0a, indices_0b, src_0, src_1); + svst1(pg_1, dst_row0, dst_0); + svfloat32_t dst_7 = + index_and_lerp2d(pg_1, indices_0a, indices_0b, src_1, src_0); + svst1(pg_1, dst_row7, dst_7); + svst1(pg_1, dst_row1, + lerp1d_vector(pg_1, 6.0 / 7, dst_0, 1.0 / 7, dst_7)); + svst1(pg_1, dst_row2, + lerp1d_vector(pg_1, 5.0 / 7, dst_0, 2.0 / 7, dst_7)); + svst1(pg_1, dst_row3, + lerp1d_vector(pg_1, 4.0 / 7, dst_0, 3.0 / 7, dst_7)); + svst1(pg_1, dst_row4, + lerp1d_vector(pg_1, 3.0 / 7, dst_0, 4.0 / 7, dst_7)); + svst1(pg_1, dst_row5, + lerp1d_vector(pg_1, 2.0 / 7, dst_0, 5.0 / 7, dst_7)); + svst1(pg_1, dst_row6, + lerp1d_vector(pg_1, 1.0 / 7, dst_0, 6.0 / 7, dst_7)); + + dst_0 = index_and_lerp2d(pg_2, indices_1a, indices_1b, src_0, src_1); + svst1_vnum(pg_2, dst_row0, 1, dst_0); + dst_7 = index_and_lerp2d(pg_2, indices_1a, indices_1b, src_1, src_0); + svst1_vnum(pg_2, dst_row7, 1, dst_7); + svst1_vnum(pg_2, dst_row1, 1, + lerp1d_vector(pg_2, 6.0 / 7, dst_0, 1.0 / 7, dst_7)); + svst1_vnum(pg_2, dst_row2, 1, + lerp1d_vector(pg_2, 5.0 / 7, dst_0, 2.0 / 7, dst_7)); + svst1_vnum(pg_2, dst_row3, 1, + lerp1d_vector(pg_2, 4.0 / 7, dst_0, 3.0 / 7, dst_7)); + svst1_vnum(pg_2, dst_row4, 1, + lerp1d_vector(pg_2, 3.0 / 7, dst_0, 4.0 / 7, dst_7)); + svst1_vnum(pg_2, dst_row5, 1, + lerp1d_vector(pg_2, 2.0 / 7, dst_0, 5.0 / 7, dst_7)); + svst1_vnum(pg_2, dst_row6, 1, + lerp1d_vector(pg_2, 1.0 / 7, dst_0, 6.0 / 7, dst_7)); + + dst_0 = index_and_lerp2d(pg_3, indices_2a, indices_2b, src_0, src_1); + svst1_vnum(pg_3, dst_row0, 2, dst_0); + dst_7 = index_and_lerp2d(pg_3, indices_2a, indices_2b, src_1, src_0); + svst1_vnum(pg_3, dst_row7, 2, dst_7); + svst1_vnum(pg_3, dst_row1, 2, + lerp1d_vector(pg_3, 6.0 / 7, dst_0, 1.0 / 7, dst_7)); + svst1_vnum(pg_3, dst_row2, 2, + lerp1d_vector(pg_3, 5.0 / 7, dst_0, 2.0 / 7, dst_7)); + svst1_vnum(pg_3, dst_row3, 2, + lerp1d_vector(pg_3, 4.0 / 7, dst_0, 3.0 / 7, dst_7)); + svst1_vnum(pg_3, dst_row4, 2, + lerp1d_vector(pg_3, 3.0 / 7, dst_0, 4.0 / 7, dst_7)); + svst1_vnum(pg_3, dst_row5, 2, + lerp1d_vector(pg_3, 2.0 / 7, dst_0, 5.0 / 7, dst_7)); + svst1_vnum(pg_3, dst_row6, 2, + lerp1d_vector(pg_3, 1.0 / 7, dst_0, 6.0 / 7, dst_7)); + + dst_0 = index_and_lerp2d(pg_4, indices_3a, indices_3b, src_0, src_1); + svst1_vnum(pg_4, dst_row0, 3, dst_0); + dst_7 = index_and_lerp2d(pg_4, indices_3a, indices_3b, src_1, src_0); + svst1_vnum(pg_4, dst_row7, 3, dst_7); + svst1_vnum(pg_4, dst_row1, 3, + lerp1d_vector(pg_4, 6.0 / 7, dst_0, 1.0 / 7, dst_7)); + svst1_vnum(pg_4, dst_row2, 3, + lerp1d_vector(pg_4, 5.0 / 7, dst_0, 2.0 / 7, dst_7)); + svst1_vnum(pg_4, dst_row3, 3, + lerp1d_vector(pg_4, 4.0 / 7, dst_0, 3.0 / 7, dst_7)); + svst1_vnum(pg_4, dst_row4, 3, + lerp1d_vector(pg_4, 3.0 / 7, dst_0, 4.0 / 7, dst_7)); + svst1_vnum(pg_4, dst_row5, 3, + lerp1d_vector(pg_4, 2.0 / 7, dst_0, 5.0 / 7, dst_7)); + svst1_vnum(pg_4, dst_row6, 3, + lerp1d_vector(pg_4, 1.0 / 7, dst_0, 6.0 / 7, dst_7)); + } + }; + + // Corners + auto set_corner = [dst, dst_stride](size_t left_column, size_t top_row, + float value) KSC { + float *row = dst + dst_stride * top_row + left_column; + for (size_t i = 0; i < 4; ++i) { + for (size_t j = 0; j < 4; ++j) { + row[j] = value; + } + row += dst_stride; + } + }; + set_corner(0, 0, src[0]); + set_corner(dst_width - 4, 0, src[src_width - 1]); + set_corner(0, dst_height - 4, src[src_stride * (src_height - 1)]); + set_corner(dst_width - 4, dst_height - 4, + src[src_stride * (src_height - 1) + src_width - 1]); + + // Left & right edge + for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { + float *dst_row = dst + dst_stride * (src_y * 8 + 4); + const float *src_row0 = src + src_stride * src_y; + const float *src_row1 = src_row0 + src_stride; + const float s0l = src_row0[0], s1l = src_row1[0]; + const float s0r = src_row0[src_width - 1], s1r = src_row1[src_width - 1]; + svbool_t pg = svptrue_pat_b32(SV_VL4); // write 4 elements + for (size_t i = 0; i < 8; ++i) { + svst1(pg, dst_row, + lerp1d_vector(pg, static_cast(15 - i * 2) / 16.0F, + svdup_f32_x(pg, s0l), + static_cast(i * 2 + 1) / 16.0F, + svdup_f32_x(pg, s1l))); + svst1(pg, dst_row + dst_width - 4, + lerp1d_vector(pg, static_cast(15 - i * 2) / 16.0F, + svdup_f32_x(pg, s0r), + static_cast(i * 2 + 1) / 16.0F, + svdup_f32_x(pg, s1r))); + dst_row += dst_stride; + } + } + + // Top rows + process_edge_row(src, dst, dst_stride); + + // Middle rows + for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { + size_t dst_y = src_y * 8 + 4; + const float *src_row0 = src + src_stride * src_y; + const float *src_row1 = src_row0 + src_stride; + process_row(src_row0, src_row1, dst + dst_stride * dst_y, dst_stride); + } + + // Bottom rows + process_edge_row(src + src_stride * (src_height - 1), + dst + dst_stride * (dst_height - 4), dst_stride); + + return KLEIDICV_OK; +} + KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_linear_u8_sc( const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, uint8_t *dst, size_t dst_stride, size_t dst_width, @@ -679,6 +1163,14 @@ KLEIDICV_TARGET_FN_ATTRS static kleidicv_error_t resize_linear_f32_sc( return resize_4x4_f32_sc(src, src_stride, src_width, src_height, dst, dst_stride); } + if (src_width * 8 == dst_width && src_height * 8 == dst_height) { + if (svcntw() >= 8) { + return resize_8x8_f32_sve256plus_sc(src, src_stride, src_width, + src_height, dst, dst_stride); + } + return resize_8x8_f32_sve128_sc(src, src_stride, src_width, src_height, dst, + dst_stride); + } return KLEIDICV_ERROR_NOT_IMPLEMENTED; } diff --git a/scripts/benchmark/run_benchmarks_4K.sh b/scripts/benchmark/run_benchmarks_4K.sh index 378b375a4d0540fd49280048d8c23dfadc6152c5..e5bab2d4b29a88ef4d436618a1b4a4eeb14c9ca0 100755 --- a/scripts/benchmark/run_benchmarks_4K.sh +++ b/scripts/benchmark/run_benchmarks_4K.sh @@ -55,6 +55,7 @@ RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize2x2_float opencv_perf_imgproc '*resizeUpLinearNonExact*' '(32FC1, (1920x1080, 3840x2160))')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize4x4_8b opencv_perf_imgproc '*resizeUpLinearNonExact*' '(8UC1, (960x540, 3840x2160))')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize4x4_float opencv_perf_imgproc '*resizeUpLinearNonExact*' '(32FC1, (960x540, 3840x2160))')") +RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize8x8_float opencv_perf_imgproc '*resizeUpLinearNonExact*' '(32FC1, (480x270, 3840x2160))')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Scale opencv_perf_core '*convertTo*' '(3840x2160, 8UC1, 8UC1, 1, 1.234, 4.567)')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Scale_float_1.0 opencv_perf_core '*convertTo*' '(3840x2160, 32FC1, 32FC1, 1, 1, 4.567)')") diff --git a/scripts/benchmark/run_benchmarks_FHD.sh b/scripts/benchmark/run_benchmarks_FHD.sh index 6db3a16a549287aaccb9f949a4aec848604a846b..b231fd02975909b9ee5a467c6eccb1ceed43ad8b 100755 --- a/scripts/benchmark/run_benchmarks_FHD.sh +++ b/scripts/benchmark/run_benchmarks_FHD.sh @@ -55,6 +55,7 @@ RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize2x2_float opencv_perf_imgproc '*resizeUpLinearNonExact*' '(32FC1, (960x540, 1920x1080))')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize4x4_8b opencv_perf_imgproc '*resizeUpLinearNonExact*' '(8UC1, (480x270, 1920x1080))')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize4x4_float opencv_perf_imgproc '*resizeUpLinearNonExact*' '(32FC1, (480x270, 1920x1080))')") +RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Resize8x8_float opencv_perf_imgproc '*resizeUpLinearNonExact*' '(32FC1, (240x135, 1920x1080))')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Scale opencv_perf_core '*convertTo*' '(1920x1080, 8UC1, 8UC1, 1, 1.234, 4.567)')") RES+=$(printf "\n$(${DEV_DIR}/perf_test_op.sh $CUSTOM_BUILD_SUFFIX $CPU $THERMAL Scale_float_1.0 opencv_perf_core '*convertTo*' '(1920x1080, 32FC1, 32FC1, 1, 1, 4.567)')") diff --git a/test/api/test_resize_linear.cpp b/test/api/test_resize_linear.cpp index 8021610b42593dcb7117049b52483fccda7fedcd..9d5f1df64b5d5c6fb783f015bf891f8cc2bec64f 100644 --- a/test/api/test_resize_linear.cpp +++ b/test/api/test_resize_linear.cpp @@ -38,172 +38,116 @@ TEST(FloatSimilar, FloatSimilar) { } template -static void resize_linear_unaccelerated_2x2(const T *src, size_t src_stride, - size_t src_width, size_t src_height, - T *dst, size_t dst_stride, - size_t dst_width, - size_t dst_height) { +static void resize_linear_unaccelerated_generic_upscale( + const T *src, size_t src_stride, size_t src_width, size_t src_height, + T *dst, size_t dst_stride, size_t dst_width, size_t dst_height) { src_stride /= sizeof(T); dst_stride /= sizeof(T); + size_t scale_width = dst_width / src_width; + size_t scale_height = dst_height / src_height; - auto lerp1d = [](T near, T far) { - constexpr T bias = std::is_floating_point_v ? 0 : 2; - return (near * 3 + far + bias) / 4; - }; - - auto lerp2d = [](T near, T mid_a, T mid_b, T far) { - constexpr T bias = std::is_floating_point_v ? 0 : 8; - return (near * 9 + (mid_a + mid_b) * 3 + far + bias) / 16; + auto lerp1d_horizontal = [scale_width](T coeff_a, T a, T coeff_b, T b) { + if constexpr (std::is_floating_point_v) { + float divisor = static_cast(2 * scale_width); + return (coeff_a / divisor * a + coeff_b / divisor * b); + } else { + T bias = scale_width; + return (coeff_a * a + coeff_b * b + bias) / (2 * scale_width); + } }; - auto process_row = [src_width, dst_width, lerp1d, lerp2d]( - const T *src_row0, const T *src_row1, T *dst_row0, - T *dst_row1) { - // Left element - dst_row0[0] = lerp1d(src_row0[0], src_row1[0]); - dst_row1[0] = lerp1d(src_row1[0], src_row0[0]); - - // Right element - dst_row0[dst_width - 1] = - lerp1d(src_row0[src_width - 1], src_row1[src_width - 1]); - dst_row1[dst_width - 1] = - lerp1d(src_row1[src_width - 1], src_row0[src_width - 1]); - - for (size_t src_x = 0; src_x + 1 < src_width; ++src_x) { - size_t dst_x = src_x * 2 + 1; - const T src_tl = src_row0[src_x], src_tr = src_row0[src_x + 1], - src_bl = src_row1[src_x], src_br = src_row1[src_x + 1]; - dst_row0[dst_x] = lerp2d(src_tl, src_tr, src_bl, src_br); - dst_row0[dst_x + 1] = lerp2d(src_tr, src_tl, src_br, src_bl); - dst_row1[dst_x] = lerp2d(src_bl, src_tl, src_br, src_tr); - dst_row1[dst_x + 1] = lerp2d(src_br, src_tr, src_bl, src_tl); + auto lerp1d_vertical = [scale_height](T coeff_a, T a, T coeff_b, T b) { + if constexpr (std::is_floating_point_v) { + float divisor = static_cast(2 * scale_height); + return (coeff_a / divisor * a + coeff_b / divisor * b); + } else { + T bias = scale_height; + return (coeff_a * a + coeff_b * b + bias) / (2 * scale_height); } }; - // Top row - process_row(src, src, dst, dst); - - // Middle rows - for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { - size_t dst_y = src_y * 2 + 1; - const T *src_row0 = src + src_stride * src_y; - const T *src_row1 = src_row0 + src_stride; - T *dst_row0 = dst + dst_stride * dst_y; - T *dst_row1 = dst_row0 + dst_stride; - - process_row(src_row0, src_row1, dst_row0, dst_row1); - } - - // Bottom row - const T *last_src_row = src + src_stride * (src_height - 1); - T *last_dst_row = dst + dst_stride * (dst_height - 1); - process_row(last_src_row, last_src_row, last_dst_row, last_dst_row); -} - -template -static void resize_linear_unaccelerated_4x4(const T *src, size_t src_stride, - size_t src_width, size_t src_height, - T *dst, size_t dst_stride, - size_t dst_width, - size_t dst_height) { - src_stride /= sizeof(T); - dst_stride /= sizeof(T); - - auto lerp1d_scalar = [](T coeff_a, T a, T coeff_b, T b) { - constexpr T bias = std::is_floating_point_v ? 0 : 4; - return (coeff_a * a + coeff_b * b + bias) / 8; - }; - auto lerp2d_scalar = [](T coeff_a, T a, T coeff_b, T b, T coeff_c, T c, - T coeff_d, T d) { - constexpr T bias = std::is_floating_point_v ? 0 : 32; - return (coeff_a * a + coeff_b * b + coeff_c * c + coeff_d * d + bias) / 64; + auto lerp2d = [scale_width, scale_height](T coeff_a, T a, T coeff_b, T b, + T coeff_c, T c, T coeff_d, T d) { + if constexpr (std::is_floating_point_v) { + float divisor = static_cast(4 * scale_height * scale_width); + return (coeff_a / divisor * a + coeff_b / divisor * b + + coeff_c / divisor * c + coeff_d / divisor * d); + } else { + T bias = 2 * scale_height * scale_width; + return (coeff_a * a + coeff_b * b + coeff_c * c + coeff_d * d + bias) / + (4 * scale_height * scale_width); + } }; // Handle top or bottom edge - auto process_edge_row = [src_width, dst_width, lerp1d_scalar]( - const T *src_row, T *dst_row) { - // Left elements - dst_row[1] = dst_row[0] = src_row[0]; - - // Right elements - dst_row[dst_width - 1] = dst_row[dst_width - 2] = src_row[src_width - 1]; - - // Middle elements - for (size_t src_x = 0; src_x + 1 < src_width; ++src_x) { - size_t dst_x = src_x * 4 + 2; - const T a = src_row[src_x], b = src_row[src_x + 1]; - dst_row[dst_x + 0] = lerp1d_scalar(7, a, 1, b); - dst_row[dst_x + 1] = lerp1d_scalar(5, a, 3, b); - dst_row[dst_x + 2] = lerp1d_scalar(3, a, 5, b); - dst_row[dst_x + 3] = lerp1d_scalar(1, a, 7, b); + auto process_edge_row = [src_width, dst_width, scale_width, scale_height, + lerp1d_horizontal](const T *src_row, T *dst_row, + size_t dst_stride) { + for (size_t y = 0; y < scale_height / 2; ++y) { + for (size_t x = 0; x < scale_width / 2; ++x) { + // Left elements + dst_row[x] = src_row[0]; + // Right elements + dst_row[dst_width - scale_width / 2 + x] = src_row[src_width - 1]; + } + // Middle elements + for (size_t src_x = 0; src_x + 1 < src_width; ++src_x) { + size_t dst_x = src_x * scale_width + scale_width / 2; + const T a = src_row[src_x], b = src_row[src_x + 1]; + for (size_t x = 0; x < scale_width; ++x) { + dst_row[dst_x + x] = + lerp1d_horizontal((scale_width - x) * 2 - 1, a, x * 2 + 1, b); + } + } + dst_row += dst_stride; } }; - auto process_row = [src_width, dst_width, lerp1d_scalar, lerp2d_scalar]( - const T *src_row0, const T *src_row1, T *dst_row0, - T *dst_row1, T *dst_row2, T *dst_row3) { - // Left elements - const T s0l = src_row0[0], s1l = src_row1[0]; - dst_row0[0] = dst_row0[1] = lerp1d_scalar(7, s0l, 1, s1l); - dst_row1[0] = dst_row1[1] = lerp1d_scalar(5, s0l, 3, s1l); - dst_row2[0] = dst_row2[1] = lerp1d_scalar(3, s0l, 5, s1l); - dst_row3[0] = dst_row3[1] = lerp1d_scalar(1, s0l, 7, s1l); - - // Right elements - const T s0r = src_row0[src_width - 1], s1r = src_row1[src_width - 1]; - const size_t dr0 = dst_width - 2; - const size_t dr1 = dst_width - 1; - dst_row0[dr0] = dst_row0[dr1] = lerp1d_scalar(7, s0r, 1, s1r); - dst_row1[dr0] = dst_row1[dr1] = lerp1d_scalar(5, s0r, 3, s1r); - dst_row2[dr0] = dst_row2[dr1] = lerp1d_scalar(3, s0r, 5, s1r); - dst_row3[dr0] = dst_row3[dr1] = lerp1d_scalar(1, s0r, 7, s1r); - - // Middle elements - for (size_t src_x = 0; src_x + 1 < src_width; ++src_x) { - size_t dst_x = src_x * 4 + 2; - const T a = src_row0[src_x], b = src_row0[src_x + 1], c = src_row1[src_x], - d = src_row1[src_x + 1]; - - dst_row0[dst_x + 0] = lerp2d_scalar(49, a, 7, b, 7, c, 1, d); - dst_row0[dst_x + 1] = lerp2d_scalar(35, a, 21, b, 5, c, 3, d); - dst_row0[dst_x + 2] = lerp2d_scalar(21, a, 35, b, 3, c, 5, d); - dst_row0[dst_x + 3] = lerp2d_scalar(7, a, 49, b, 1, c, 7, d); - dst_row1[dst_x + 0] = lerp2d_scalar(35, a, 5, b, 21, c, 3, d); - dst_row1[dst_x + 1] = lerp2d_scalar(25, a, 15, b, 15, c, 9, d); - dst_row1[dst_x + 2] = lerp2d_scalar(15, a, 25, b, 9, c, 15, d); - dst_row1[dst_x + 3] = lerp2d_scalar(5, a, 35, b, 3, c, 21, d); - dst_row2[dst_x + 0] = lerp2d_scalar(21, a, 3, b, 35, c, 5, d); - dst_row2[dst_x + 1] = lerp2d_scalar(15, a, 9, b, 25, c, 15, d); - dst_row2[dst_x + 2] = lerp2d_scalar(9, a, 15, b, 15, c, 25, d); - dst_row2[dst_x + 3] = lerp2d_scalar(3, a, 21, b, 5, c, 35, d); - dst_row3[dst_x + 0] = lerp2d_scalar(7, a, 1, b, 49, c, 7, d); - dst_row3[dst_x + 1] = lerp2d_scalar(5, a, 3, b, 35, c, 21, d); - dst_row3[dst_x + 2] = lerp2d_scalar(3, a, 5, b, 21, c, 35, d); - dst_row3[dst_x + 3] = lerp2d_scalar(1, a, 7, b, 7, c, 49, d); + auto process_row = [src_width, dst_width, scale_width, scale_height, + lerp1d_vertical, + lerp2d](const T *src_row0, const T *src_row1, T *dst_row, + size_t dst_stride) { + for (size_t y = 0; y < scale_height; ++y) { + for (size_t x = 0; x < scale_width / 2; ++x) { + // Left elements + dst_row[x] = lerp1d_vertical((scale_height - y) * 2 - 1, src_row0[0], + y * 2 + 1, src_row1[0]); + // Right elements + dst_row[dst_width - scale_width / 2 + x] = + lerp1d_vertical((scale_height - y) * 2 - 1, src_row0[src_width - 1], + y * 2 + 1, src_row1[src_width - 1]); + } + // Middle elements + for (size_t src_x = 0; src_x + 1 < src_width; ++src_x) { + size_t dst_x = src_x * scale_width + scale_width / 2; + const T a = src_row0[src_x], b = src_row0[src_x + 1]; + const T c = src_row1[src_x], d = src_row1[src_x + 1]; + for (size_t x = 0; x < scale_width; ++x) { + dst_row[dst_x + x] = + lerp2d(((scale_width - x) * 2 - 1) * ((scale_height - y) * 2 - 1), + a, (x * 2 + 1) * ((scale_height - y) * 2 - 1), b, + ((scale_width - x) * 2 - 1) * (y * 2 + 1), c, + (x * 2 + 1) * (y * 2 + 1), d); + } + } + dst_row += dst_stride; } }; // Top rows - process_edge_row(src, dst); - memcpy(dst + dst_stride, dst, dst_stride * sizeof(T)); + process_edge_row(src, dst, dst_stride); // Middle rows for (size_t src_y = 0; src_y + 1 < src_height; ++src_y) { - size_t dst_y = src_y * 4 + 2; + size_t dst_y = src_y * scale_height + scale_height / 2; const T *src_row0 = src + src_stride * src_y; const T *src_row1 = src_row0 + src_stride; - T *dst_row0 = dst + dst_stride * dst_y; - T *dst_row1 = dst_row0 + dst_stride; - T *dst_row2 = dst_row1 + dst_stride; - T *dst_row3 = dst_row2 + dst_stride; - - process_row(src_row0, src_row1, dst_row0, dst_row1, dst_row2, dst_row3); + process_row(src_row0, src_row1, dst + dst_stride * dst_y, dst_stride); } // Bottom rows process_edge_row(src + src_stride * (src_height - 1), - dst + dst_stride * (dst_height - 2)); - memcpy(dst + dst_stride * (dst_height - 1), - dst + dst_stride * (dst_height - 2), dst_stride * sizeof(T)); + dst + dst_stride * (dst_height - scale_height / 2), + dst_stride); } template @@ -211,13 +155,13 @@ static void resize_linear_unaccelerated(const T *src, size_t src_stride, size_t src_width, size_t src_height, T *dst, size_t dst_stride, size_t dst_width, size_t dst_height) { - if (src_width * 2 == dst_width && src_height * 2 == dst_height) { - resize_linear_unaccelerated_2x2(src, src_stride, src_width, src_height, dst, - dst_stride, dst_width, dst_height); - } - if (src_width * 4 == dst_width && src_height * 4 == dst_height) { - resize_linear_unaccelerated_4x4(src, src_stride, src_width, src_height, dst, - dst_stride, dst_width, dst_height); + // even integer scaling + if (src_width > 0 && src_height > 0 && dst_width % src_width == 0 && + dst_height % src_height == 0 && (dst_width / src_width) % 2 == 0 && + (dst_height / src_height) % 2 == 0) { + resize_linear_unaccelerated_generic_upscale(src, src_stride, src_width, + src_height, dst, dst_stride, + dst_width, dst_height); } } @@ -365,6 +309,19 @@ TYPED_TEST(ResizeLinear, LargeDimensions4x4) { do_large_dimensions_test(4, 4); } +TEST(ResizeLinearFloat, LargeDimensions8x8) { + do_large_dimensions_test(8, 8); +} + +TEST(ResizeLinearU8, NotImplemented_8x8) { + const uint8_t src[1] = {}; + uint8_t dst[4]; + + EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, + kleidicv_resize_linear(src, sizeof(uint8_t), 1, 1, dst, + sizeof(uint8_t) * 8, 8, 8)); +} + // Parameterised tests template struct ResizeTestParams { @@ -1000,4 +957,1035 @@ INSTANTIATE_TEST_SUITE_P( 24.625F, 28.875F, 42.625F, 65.875F, 89.125F, 112.375F, 136.125F, 160.375F, 184.625F, 208.875F, 220.125F, 218.375F, 216.625F, 214.875F, 205.5F, 188.5F, 171.5F, 154.5F, - 146, 146}}})); + 146, 146}}}, + // 2*2 -> 16*16 + Pf32{{{FLT_MAX, 1e38F}, {0, FLT_TRUE_MIN}}, + { + {3.402823466e+38F, 3.402823466e+38F, 3.402823466e+38F, + 3.402823466e+38F, 3.252647029e+38F, 2.952294156e+38F, + 2.651941079e+38F, 2.351588205e+38F, 2.051235331e+38F, + 1.750882254e+38F, 1.45052938e+38F, 1.150176405e+38F, + 9.99999968e+37F, 9.99999968e+37F, 9.99999968e+37F, + 9.99999968e+37F}, + {3.402823466e+38F, 3.402823466e+38F, 3.402823466e+38F, + 3.402823466e+38F, 3.252647029e+38F, 2.952294156e+38F, + 2.651941079e+38F, 2.351588205e+38F, 2.051235331e+38F, + 1.750882254e+38F, 1.45052938e+38F, 1.150176405e+38F, + 9.99999968e+37F, 9.99999968e+37F, 9.99999968e+37F, + 9.99999968e+37F}, + {3.402823466e+38F, 3.402823466e+38F, 3.402823466e+38F, + 3.402823466e+38F, 3.252647029e+38F, 2.952294156e+38F, + 2.651941079e+38F, 2.351588205e+38F, 2.051235331e+38F, + 1.750882254e+38F, 1.45052938e+38F, 1.150176405e+38F, + 9.99999968e+37F, 9.99999968e+37F, 9.99999968e+37F, + 9.99999968e+37F}, + {3.402823466e+38F, 3.402823466e+38F, 3.402823466e+38F, + 3.402823466e+38F, 3.252647029e+38F, 2.952294156e+38F, + 2.651941079e+38F, 2.351588205e+38F, 2.051235331e+38F, + 1.750882254e+38F, 1.45052938e+38F, 1.150176405e+38F, + 9.99999968e+37F, 9.99999968e+37F, 9.99999968e+37F, + 9.99999968e+37F}, + {3.190146987e+38F, 3.190146987e+38F, 3.190146987e+38F, + 3.190146987e+38F, 3.049356641e+38F, 2.767775745e+38F, + 2.48619485e+38F, 2.204613955e+38F, 1.923033059e+38F, + 1.641452164e+38F, 1.359871269e+38F, 1.078290373e+38F, + 9.374999257e+37F, 9.374999257e+37F, 9.374999257e+37F, + 9.374999257e+37F}, + {2.764794028e+38F, 2.764794028e+38F, 2.764794028e+38F, + 2.764794028e+38F, 2.642775661e+38F, 2.398738925e+38F, + 2.15470219e+38F, 1.910665454e+38F, 1.666628618e+38F, + 1.422591882e+38F, 1.178555147e+38F, 9.3451831e+37F, + 8.12499993e+37F, 8.12499993e+37F, 8.12499993e+37F, + 8.12499993e+37F}, + {2.33944107e+38F, 2.33944107e+38F, 2.33944107e+38F, + 2.33944107e+38F, 2.236194883e+38F, 2.029702105e+38F, + 1.82320953e+38F, 1.616716853e+38F, 1.410224277e+38F, + 1.2037316e+38F, 9.972389236e+37F, 7.907462974e+37F, + 6.87499959e+37F, 6.87499959e+37F, 6.87499959e+37F, + 6.87499959e+37F}, + {1.914088111e+38F, 1.914088111e+38F, 1.914088111e+38F, + 1.914088111e+38F, 1.829613903e+38F, 1.660665386e+38F, + 1.491716869e+38F, 1.322768353e+38F, 1.153819836e+38F, + 9.848713187e+37F, 8.159228018e+37F, 6.469742341e+37F, + 5.624999757e+37F, 5.624999757e+37F, 5.624999757e+37F, + 5.624999757e+37F}, + {1.488735254e+38F, 1.488735254e+38F, 1.488735254e+38F, + 1.488735254e+38F, 1.423033025e+38F, 1.291628668e+38F, + 1.160224209e+38F, 1.028819852e+38F, 8.974153939e+37F, + 7.660109862e+37F, 6.346066292e+37F, 5.032021708e+37F, + 4.374999924e+37F, 4.374999924e+37F, 4.374999924e+37F, + 4.374999924e+37F}, + {1.063382295e+38F, 1.063382295e+38F, 1.063382295e+38F, + 1.063382295e+38F, 1.016452146e+38F, 9.225918475e+37F, + 8.287315998e+37F, 7.348713013e+37F, 6.410110029e+37F, + 5.471507044e+37F, 4.53290406e+37F, 3.594301329e+37F, + 3.124999837e+37F, 3.124999837e+37F, 3.124999837e+37F, + 3.124999837e+37F}, + {6.380293873e+37F, 6.380293873e+37F, 6.380293873e+37F, + 6.380293873e+37F, 6.09871318e+37F, 5.535551288e+37F, + 4.972389396e+37F, 4.409228011e+37F, 3.846066119e+37F, + 3.28290448e+37F, 2.719742588e+37F, 2.156580696e+37F, + 1.875000003e+37F, 1.875000003e+37F, 1.875000003e+37F, + 1.875000003e+37F}, + {2.126764666e+37F, 2.126764666e+37F, 2.126764666e+37F, + 2.126764666e+37F, 2.032904393e+37F, 1.845183847e+37F, + 1.657463174e+37F, 1.469742628e+37F, 1.282022082e+37F, + 1.094301409e+37F, 9.065808627e+36F, 7.188602531e+36F, + 6.2499998e+36F, 6.2499998e+36F, 6.2499998e+36F, + 6.2499998e+36F}, + {0, 0, 0, 0, 0, 0, 0, 0, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F}, + {0, 0, 0, 0, 0, 0, 0, 0, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F}, + {0, 0, 0, 0, 0, 0, 0, 0, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F}, + {0, 0, 0, 0, 0, 0, 0, 0, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F, + 1.401298464e-45F, 1.401298464e-45F, 1.401298464e-45F}, + }}, + // 35*2 -> 280*16 + Pf32{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 82, + 155, 104, 108, 227, 46, 162, 21, 220, 235, 183, 113, 225, + 146, 196, 144, 104, 148, 19, 126, 172, 9, 12, 61}, + {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 193, + 44, 105, 191, 106, 73, 148, 13, 161, 118, 21, 3, 34, + 40, 150, 120, 68, 75, 14, 31, 124, 221, 214, 146}}, + {{0, 0, 0, 0, 0.0625F, 0.1875F, + 0.3125F, 0.4375F, 0.5625F, 0.6875F, 0.8125F, 0.9375F, + 1.0625F, 1.1875F, 1.3125F, 1.4375F, 1.5625F, 1.6875F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, 2.3125F, 2.4375F, + 2.5625F, 2.6875F, 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, 3.8125F, 3.9375F, + 4.0625F, 4.1875F, 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, 5.3125F, 5.4375F, + 5.5625F, 5.6875F, 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, 6.8125F, 6.9375F, + 7.0625F, 7.1875F, 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, 8.3125F, 8.4375F, + 8.5625F, 8.6875F, 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, 9.8125F, 9.9375F, + 14.5F, 23.5F, 32.5F, 41.5F, 50.5F, 59.5F, + 68.5F, 77.5F, 86.5625F, 95.6875F, 104.8125F, 113.9375F, + 123.0625F, 132.1875F, 141.3125F, 150.4375F, 151.8125F, 145.4375F, + 139.0625F, 132.6875F, 126.3125F, 119.9375F, 113.5625F, 107.1875F, + 104.25F, 104.75F, 105.25F, 105.75F, 106.25F, 106.75F, + 107.25F, 107.75F, 115.4375F, 130.3125F, 145.1875F, 160.0625F, + 174.9375F, 189.8125F, 204.6875F, 219.5625F, 215.6875F, 193.0625F, + 170.4375F, 147.8125F, 125.1875F, 102.5625F, 79.9375F, 57.3125F, + 53.25F, 67.75F, 82.25F, 96.75F, 111.25F, 125.75F, + 140.25F, 154.75F, 153.1875F, 135.5625F, 117.9375F, 100.3125F, + 82.6875F, 65.0625F, 47.4375F, 29.8125F, 33.4375F, 58.3125F, + 83.1875F, 108.0625F, 132.9375F, 157.8125F, 182.6875F, 207.5625F, + 220.9375F, 222.8125F, 224.6875F, 226.5625F, 228.4375F, 230.3125F, + 232.1875F, 234.0625F, 231.75F, 225.25F, 218.75F, 212.25F, + 205.75F, 199.25F, 192.75F, 186.25F, 178.625F, 169.875F, + 161.125F, 152.375F, 143.625F, 134.875F, 126.125F, 117.375F, + 120.0F, 134.0F, 148.0F, 162.0F, 176.0F, 190.0F, + 204.0F, 218.0F, 220.0625F, 210.1875F, 200.3125F, 190.4375F, + 180.5625F, 170.6875F, 160.8125F, 150.9375F, 149.125F, 155.375F, + 161.625F, 167.875F, 174.125F, 180.375F, 186.625F, 192.875F, + 192.75F, 186.25F, 179.75F, 173.25F, 166.75F, 160.25F, + 153.75F, 147.25F, 141.5F, 136.5F, 131.5F, 126.5F, + 121.5F, 116.5F, 111.5F, 106.5F, 106.75F, 112.25F, + 117.75F, 123.25F, 128.75F, 134.25F, 139.75F, 145.25F, + 139.9375F, 123.8125F, 107.6875F, 91.5625F, 75.4375F, 59.3125F, + 43.1875F, 27.0625F, 25.6875F, 39.0625F, 52.4375F, 65.8125F, + 79.1875F, 92.5625F, 105.9375F, 119.3125F, 128.875F, 134.625F, + 140.375F, 146.125F, 151.875F, 157.625F, 163.375F, 169.125F, + 161.8125F, 141.4375F, 121.0625F, 100.6875F, 80.3125F, 59.9375F, + 39.5625F, 19.1875F, 9.1875F, 9.5625F, 9.9375F, 10.3125F, + 10.6875F, 11.0625F, 11.4375F, 11.8125F, 15.0625F, 21.1875F, + 27.3125F, 33.4375F, 39.5625F, 45.6875F, 51.8125F, 57.9375F, + 61.0F, 61.0F, 61.0F, 61.0F}, + {0, 0, 0, 0, 0.0625F, 0.1875F, + 0.3125F, 0.4375F, 0.5625F, 0.6875F, 0.8125F, 0.9375F, + 1.0625F, 1.1875F, 1.3125F, 1.4375F, 1.5625F, 1.6875F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, 2.3125F, 2.4375F, + 2.5625F, 2.6875F, 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, 3.8125F, 3.9375F, + 4.0625F, 4.1875F, 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, 5.3125F, 5.4375F, + 5.5625F, 5.6875F, 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, 6.8125F, 6.9375F, + 7.0625F, 7.1875F, 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, 8.3125F, 8.4375F, + 8.5625F, 8.6875F, 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, 9.8125F, 9.9375F, + 14.5F, 23.5F, 32.5F, 41.5F, 50.5F, 59.5F, + 68.5F, 77.5F, 86.5625F, 95.6875F, 104.8125F, 113.9375F, + 123.0625F, 132.1875F, 141.3125F, 150.4375F, 151.8125F, 145.4375F, + 139.0625F, 132.6875F, 126.3125F, 119.9375F, 113.5625F, 107.1875F, + 104.25F, 104.75F, 105.25F, 105.75F, 106.25F, 106.75F, + 107.25F, 107.75F, 115.4375F, 130.3125F, 145.1875F, 160.0625F, + 174.9375F, 189.8125F, 204.6875F, 219.5625F, 215.6875F, 193.0625F, + 170.4375F, 147.8125F, 125.1875F, 102.5625F, 79.9375F, 57.3125F, + 53.25F, 67.75F, 82.25F, 96.75F, 111.25F, 125.75F, + 140.25F, 154.75F, 153.1875F, 135.5625F, 117.9375F, 100.3125F, + 82.6875F, 65.0625F, 47.4375F, 29.8125F, 33.4375F, 58.3125F, + 83.1875F, 108.0625F, 132.9375F, 157.8125F, 182.6875F, 207.5625F, + 220.9375F, 222.8125F, 224.6875F, 226.5625F, 228.4375F, 230.3125F, + 232.1875F, 234.0625F, 231.75F, 225.25F, 218.75F, 212.25F, + 205.75F, 199.25F, 192.75F, 186.25F, 178.625F, 169.875F, + 161.125F, 152.375F, 143.625F, 134.875F, 126.125F, 117.375F, + 120.0F, 134.0F, 148.0F, 162.0F, 176.0F, 190.0F, + 204.0F, 218.0F, 220.0625F, 210.1875F, 200.3125F, 190.4375F, + 180.5625F, 170.6875F, 160.8125F, 150.9375F, 149.125F, 155.375F, + 161.625F, 167.875F, 174.125F, 180.375F, 186.625F, 192.875F, + 192.75F, 186.25F, 179.75F, 173.25F, 166.75F, 160.25F, + 153.75F, 147.25F, 141.5F, 136.5F, 131.5F, 126.5F, + 121.5F, 116.5F, 111.5F, 106.5F, 106.75F, 112.25F, + 117.75F, 123.25F, 128.75F, 134.25F, 139.75F, 145.25F, + 139.9375F, 123.8125F, 107.6875F, 91.5625F, 75.4375F, 59.3125F, + 43.1875F, 27.0625F, 25.6875F, 39.0625F, 52.4375F, 65.8125F, + 79.1875F, 92.5625F, 105.9375F, 119.3125F, 128.875F, 134.625F, + 140.375F, 146.125F, 151.875F, 157.625F, 163.375F, 169.125F, + 161.8125F, 141.4375F, 121.0625F, 100.6875F, 80.3125F, 59.9375F, + 39.5625F, 19.1875F, 9.1875F, 9.5625F, 9.9375F, 10.3125F, + 10.6875F, 11.0625F, 11.4375F, 11.8125F, 15.0625F, 21.1875F, + 27.3125F, 33.4375F, 39.5625F, 45.6875F, 51.8125F, 57.9375F, + 61.0F, 61.0F, 61.0F, 61.0F}, + {0, 0, 0, 0, 0.0625F, 0.1875F, + 0.3125F, 0.4375F, 0.5625F, 0.6875F, 0.8125F, 0.9375F, + 1.0625F, 1.1875F, 1.3125F, 1.4375F, 1.5625F, 1.6875F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, 2.3125F, 2.4375F, + 2.5625F, 2.6875F, 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, 3.8125F, 3.9375F, + 4.0625F, 4.1875F, 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, 5.3125F, 5.4375F, + 5.5625F, 5.6875F, 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, 6.8125F, 6.9375F, + 7.0625F, 7.1875F, 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, 8.3125F, 8.4375F, + 8.5625F, 8.6875F, 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, 9.8125F, 9.9375F, + 14.5F, 23.5F, 32.5F, 41.5F, 50.5F, 59.5F, + 68.5F, 77.5F, 86.5625F, 95.6875F, 104.8125F, 113.9375F, + 123.0625F, 132.1875F, 141.3125F, 150.4375F, 151.8125F, 145.4375F, + 139.0625F, 132.6875F, 126.3125F, 119.9375F, 113.5625F, 107.1875F, + 104.25F, 104.75F, 105.25F, 105.75F, 106.25F, 106.75F, + 107.25F, 107.75F, 115.4375F, 130.3125F, 145.1875F, 160.0625F, + 174.9375F, 189.8125F, 204.6875F, 219.5625F, 215.6875F, 193.0625F, + 170.4375F, 147.8125F, 125.1875F, 102.5625F, 79.9375F, 57.3125F, + 53.25F, 67.75F, 82.25F, 96.75F, 111.25F, 125.75F, + 140.25F, 154.75F, 153.1875F, 135.5625F, 117.9375F, 100.3125F, + 82.6875F, 65.0625F, 47.4375F, 29.8125F, 33.4375F, 58.3125F, + 83.1875F, 108.0625F, 132.9375F, 157.8125F, 182.6875F, 207.5625F, + 220.9375F, 222.8125F, 224.6875F, 226.5625F, 228.4375F, 230.3125F, + 232.1875F, 234.0625F, 231.75F, 225.25F, 218.75F, 212.25F, + 205.75F, 199.25F, 192.75F, 186.25F, 178.625F, 169.875F, + 161.125F, 152.375F, 143.625F, 134.875F, 126.125F, 117.375F, + 120.0F, 134.0F, 148.0F, 162.0F, 176.0F, 190, + 204.0F, 218.0F, 220.0625F, 210.1875F, 200.3125F, 190.4375F, + 180.5625F, 170.6875F, 160.8125F, 150.9375F, 149.125F, 155.375F, + 161.625F, 167.875F, 174.125F, 180.375F, 186.625F, 192.875F, + 192.75F, 186.25F, 179.75F, 173.25F, 166.75F, 160.25F, + 153.75F, 147.25F, 141.5F, 136.5F, 131.5F, 126.5F, + 121.5F, 116.5F, 111.5F, 106.5F, 106.75F, 112.25F, + 117.75F, 123.25F, 128.75F, 134.25F, 139.75F, 145.25F, + 139.9375F, 123.8125F, 107.6875F, 91.5625F, 75.4375F, 59.3125F, + 43.1875F, 27.0625F, 25.6875F, 39.0625F, 52.4375F, 65.8125F, + 79.1875F, 92.5625F, 105.9375F, 119.3125F, 128.875F, 134.625F, + 140.375F, 146.125F, 151.875F, 157.625F, 163.375F, 169.125F, + 161.8125F, 141.4375F, 121.0625F, 100.6875F, 80.3125F, 59.9375F, + 39.5625F, 19.1875F, 9.1875F, 9.5625F, 9.9375F, 10.3125F, + 10.6875F, 11.0625F, 11.4375F, 11.8125F, 15.0625F, 21.1875F, + 27.3125F, 33.4375F, 39.5625F, 45.6875F, 51.8125F, 57.9375F, + 61.0F, 61.0F, 61.0F, 61.0F}, + {0, 0, 0, 0, 0.0625F, 0.1875F, + 0.3125F, 0.4375F, 0.5625F, 0.6875F, 0.8125F, 0.9375F, + 1.0625F, 1.1875F, 1.3125F, 1.4375F, 1.5625F, 1.6875F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, 2.3125F, 2.4375F, + 2.5625F, 2.6875F, 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, 3.8125F, 3.9375F, + 4.0625F, 4.1875F, 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, 5.3125F, 5.4375F, + 5.5625F, 5.6875F, 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, 6.8125F, 6.9375F, + 7.0625F, 7.1875F, 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, 8.3125F, 8.4375F, + 8.5625F, 8.6875F, 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, 9.8125F, 9.9375F, + 14.5F, 23.5F, 32.5F, 41.5F, 50.5F, 59.5F, + 68.5F, 77.5F, 86.5625F, 95.6875F, 104.8125F, 113.9375F, + 123.0625F, 132.1875F, 141.3125F, 150.4375F, 151.8125F, 145.4375F, + 139.0625F, 132.6875F, 126.3125F, 119.9375F, 113.5625F, 107.1875F, + 104.25F, 104.75F, 105.25F, 105.75F, 106.25F, 106.75F, + 107.25F, 107.75F, 115.4375F, 130.3125F, 145.1875F, 160.0625F, + 174.9375F, 189.8125F, 204.6875F, 219.5625F, 215.6875F, 193.0625F, + 170.4375F, 147.8125F, 125.1875F, 102.5625F, 79.9375F, 57.3125F, + 53.25F, 67.75F, 82.25F, 96.75F, 111.25F, 125.75F, + 140.25F, 154.75F, 153.1875F, 135.5625F, 117.9375F, 100.3125F, + 82.6875F, 65.0625F, 47.4375F, 29.8125F, 33.4375F, 58.3125F, + 83.1875F, 108.0625F, 132.9375F, 157.8125F, 182.6875F, 207.5625F, + 220.9375F, 222.8125F, 224.6875F, 226.5625F, 228.4375F, 230.3125F, + 232.1875F, 234.0625F, 231.75F, 225.25F, 218.75F, 212.25F, + 205.75F, 199.25F, 192.75F, 186.25F, 178.625F, 169.875F, + 161.125F, 152.375F, 143.625F, 134.875F, 126.125F, 117.375F, + 120, 134.0F, 148.0F, 162.0F, 176.0F, 190, + 204.0F, 218.0F, 220.0625F, 210.1875F, 200.3125F, 190.4375F, + 180.5625F, 170.6875F, 160.8125F, 150.9375F, 149.125F, 155.375F, + 161.625F, 167.875F, 174.125F, 180.375F, 186.625F, 192.875F, + 192.75F, 186.25F, 179.75F, 173.25F, 166.75F, 160.25F, + 153.75F, 147.25F, 141.5F, 136.5F, 131.5F, 126.5F, + 121.5F, 116.5F, 111.5F, 106.5F, 106.75F, 112.25F, + 117.75F, 123.25F, 128.75F, 134.25F, 139.75F, 145.25F, + 139.9375F, 123.8125F, 107.6875F, 91.5625F, 75.4375F, 59.3125F, + 43.1875F, 27.0625F, 25.6875F, 39.0625F, 52.4375F, 65.8125F, + 79.1875F, 92.5625F, 105.9375F, 119.3125F, 128.875F, 134.625F, + 140.375F, 146.125F, 151.875F, 157.625F, 163.375F, 169.125F, + 161.8125F, 141.4375F, 121.0625F, 100.6875F, 80.3125F, 59.9375F, + 39.5625F, 19.1875F, 9.1875F, 9.5625F, 9.9375F, 10.3125F, + 10.6875F, 11.0625F, 11.4375F, 11.8125F, 15.0625F, 21.1875F, + 27.3125F, 33.4375F, 39.5625F, 45.6875F, 51.8125F, 57.9375F, + 61.0F, 61.0F, 61.0F, 61.0F}, + {0.25F, 0.25F, 0.25F, 0.25F, + 0.3125F, 0.4375F, 0.5625F, 0.6875F, + 0.8125F, 0.9375F, 1.0625F, 1.1875F, + 1.3125F, 1.4375F, 1.5625F, 1.6875F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, + 2.3125F, 2.4375F, 2.5625F, 2.6875F, + 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 15.16796875F, 25.00390625F, 34.83984375F, 44.67578125F, + 54.51171875F, 64.34765625F, 74.18359375F, 84.01953125F, + 92.6328125F, 100.0234375F, 107.4140625F, 114.8046875F, + 122.1953125F, 129.5859375F, 136.9765625F, 144.3671875F, + 145.3125F, 139.8125F, 134.3125F, 128.8125F, + 123.3125F, 117.8125F, 112.3125F, 106.8125F, + 104.6328125F, 105.7734375F, 106.9140625F, 108.0546875F, + 109.1953125F, 110.3359375F, 111.4765625F, 112.6171875F, + 119.828125F, 133.109375F, 146.390625F, 159.671875F, + 172.953125F, 186.234375F, 199.515625F, 212.796875F, + 208.703125F, 187.234375F, 165.765625F, 144.296875F, + 122.828125F, 101.359375F, 79.890625F, 58.421875F, + 54.77734375F, 68.95703125F, 83.13671875F, 97.31640625F, + 111.4960938F, 125.6757812F, 139.8554688F, 154.0351562F, + 152.3359375F, 134.7578125F, 117.1796875F, 99.6015625F, + 82.0234375F, 64.4453125F, 46.8671875F, 29.2890625F, + 32.73828125F, 57.21484375F, 81.69140625F, 106.1679688F, + 130.6445312F, 155.1210938F, 179.5976562F, 204.0742188F, + 217.0234375F, 218.4453125F, 219.8671875F, 221.2890625F, + 222.7109375F, 224.1328125F, 225.5546875F, 226.9765625F, + 224.2617188F, 217.4101562F, 210.5585938F, 203.7070312F, + 196.8554688F, 190.0039062F, 183.1523438F, 176.3007812F, + 168.703125F, 160.359375F, 152.015625F, 143.671875F, + 135.328125F, 126.984375F, 118.640625F, 110.296875F, + 112.8085938F, 126.1757812F, 139.5429688F, 152.9101562F, + 166.2773438F, 179.6445312F, 193.0117188F, 206.3789062F, + 208.4570312F, 199.2460938F, 190.0351562F, 180.8242188F, + 171.6132812F, 162.4023438F, 153.1914062F, 143.9804688F, + 142.734375F, 149.453125F, 156.171875F, 162.890625F, + 169.609375F, 176.328125F, 183.046875F, 189.765625F, + 189.9609375F, 183.6328125F, 177.3046875F, 170.9765625F, + 164.6484375F, 158.3203125F, 151.9921875F, 145.6640625F, + 139.953125F, 134.859375F, 129.765625F, 124.671875F, + 119.578125F, 114.484375F, 109.390625F, 104.296875F, + 104.3554688F, 109.5664062F, 114.7773438F, 119.9882812F, + 125.1992188F, 130.4101562F, 135.6210938F, 140.8320312F, + 135.640625F, 120.046875F, 104.453125F, 88.859375F, + 73.265625F, 57.671875F, 42.078125F, 26.484375F, + 25.0234375F, 37.6953125F, 50.3671875F, 63.0390625F, + 75.7109375F, 88.3828125F, 101.0546875F, 113.7265625F, + 123.1210938F, 129.2382812F, 135.3554688F, 141.4726562F, + 147.5898438F, 153.7070312F, 159.8242188F, 165.9414062F, + 159.828125F, 141.484375F, 123.140625F, 104.796875F, + 86.453125F, 68.109375F, 49.765625F, 31.421875F, + 22.3984375F, 22.6953125F, 22.9921875F, 23.2890625F, + 23.5859375F, 23.8828125F, 24.1796875F, 24.4765625F, + 27.23046875F, 32.44140625F, 37.65234375F, 42.86328125F, + 48.07421875F, 53.28515625F, 58.49609375F, 63.70703125F, + 66.3125F, 66.3125F, 66.3125F, 66.3125F}, + {0.75F, 0.75F, 0.75F, 0.75F, + 0.8125F, 0.9375F, 1.0625F, 1.1875F, + 1.3125F, 1.4375F, 1.5625F, 1.6875F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, + 2.3125F, 2.4375F, 2.5625F, 2.6875F, + 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, + 16.50390625F, 28.01171875F, 39.51953125F, 51.02734375F, + 62.53515625F, 74.04296875F, 85.55078125F, 97.05859375F, + 104.7734375F, 108.6953125F, 112.6171875F, 116.5390625F, + 120.4609375F, 124.3828125F, 128.3046875F, 132.2265625F, + 132.3125F, 128.5625F, 124.8125F, 121.0625F, + 117.3125F, 113.5625F, 109.8125F, 106.0625F, + 105.3984375F, 107.8203125F, 110.2421875F, 112.6640625F, + 115.0859375F, 117.5078125F, 119.9296875F, 122.3515625F, + 128.609375F, 138.703125F, 148.796875F, 158.890625F, + 168.984375F, 179.078125F, 189.171875F, 199.265625F, + 194.734375F, 175.578125F, 156.421875F, 137.265625F, + 118.109375F, 98.953125F, 79.796875F, 60.640625F, + 57.83203125F, 71.37109375F, 84.91015625F, 98.44921875F, + 111.9882812F, 125.5273438F, 139.0664062F, 152.6054688F, + 150.6328125F, 133.1484375F, 115.6640625F, 98.1796875F, + 80.6953125F, 63.2109375F, 45.7265625F, 28.2421875F, + 31.33984375F, 55.01953125F, 78.69921875F, 102.3789062F, + 126.0585938F, 149.7382812F, 173.4179688F, 197.0976562F, + 209.1953125F, 209.7109375F, 210.2265625F, 210.7421875F, + 211.2578125F, 211.7734375F, 212.2890625F, 212.8046875F, + 209.2851562F, 201.7304688F, 194.1757812F, 186.6210938F, + 179.0664062F, 171.5117188F, 163.9570312F, 156.4023438F, + 148.859375F, 141.328125F, 133.796875F, 126.265625F, + 118.734375F, 111.203125F, 103.671875F, 96.140625F, + 98.42578125F, 110.5273438F, 122.6289062F, 134.7304688F, + 146.8320312F, 158.9335938F, 171.0351562F, 183.1367188F, + 185.2460938F, 177.3632812F, 169.4804688F, 161.5976562F, + 153.7148438F, 145.8320312F, 137.9492188F, 130.0664062F, + 129.953125F, 137.609375F, 145.265625F, 152.921875F, + 160.578125F, 168.234375F, 175.890625F, 183.546875F, + 184.3828125F, 178.3984375F, 172.4140625F, 166.4296875F, + 160.4453125F, 154.4609375F, 148.4765625F, 142.4921875F, + 136.859375F, 131.578125F, 126.296875F, 121.015625F, + 115.734375F, 110.453125F, 105.171875F, 99.890625F, + 99.56640625F, 104.1992188F, 108.8320312F, 113.4648438F, + 118.0976562F, 122.7304688F, 127.3632812F, 131.9960938F, + 127.046875F, 112.515625F, 97.984375F, 83.453125F, + 68.921875F, 54.390625F, 39.859375F, 25.328125F, + 23.6953125F, 34.9609375F, 46.2265625F, 57.4921875F, + 68.7578125F, 80.0234375F, 91.2890625F, 102.5546875F, + 111.6132812F, 118.4648438F, 125.3164062F, 132.1679688F, + 139.0195312F, 145.8710938F, 152.7226562F, 159.5742188F, + 155.859375F, 141.578125F, 127.296875F, 113.015625F, + 98.734375F, 84.453125F, 70.171875F, 55.890625F, + 48.8203125F, 48.9609375F, 49.1015625F, 49.2421875F, + 49.3828125F, 49.5234375F, 49.6640625F, 49.8046875F, + 51.56640625F, 54.94921875F, 58.33203125F, 61.71484375F, + 65.09765625F, 68.48046875F, 71.86328125F, 75.24609375F, + 76.9375F, 76.9375F, 76.9375F, 76.9375F}, + {1.25F, 1.25F, 1.25F, 1.25F, + 1.3125F, 1.4375F, 1.5625F, 1.6875F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, + 2.3125F, 2.4375F, 2.5625F, 2.6875F, + 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, + 10.8125F, 10.9375F, 11.0625F, 11.1875F, + 17.83984375F, 31.01953125F, 44.19921875F, 57.37890625F, + 70.55859375F, 83.73828125F, 96.91796875F, 110.0976562F, + 116.9140625F, 117.3671875F, 117.8203125F, 118.2734375F, + 118.7265625F, 119.1796875F, 119.6328125F, 120.0859375F, + 119.3125F, 117.3125F, 115.3125F, 113.3125F, + 111.3125F, 109.3125F, 107.3125F, 105.3125F, + 106.1640625F, 109.8671875F, 113.5703125F, 117.2734375F, + 120.9765625F, 124.6796875F, 128.3828125F, 132.0859375F, + 137.390625F, 144.296875F, 151.203125F, 158.109375F, + 165.015625F, 171.921875F, 178.828125F, 185.734375F, + 180.765625F, 163.921875F, 147.078125F, 130.234375F, + 113.390625F, 96.546875F, 79.703125F, 62.859375F, + 60.88671875F, 73.78515625F, 86.68359375F, 99.58203125F, + 112.4804688F, 125.3789062F, 138.2773438F, 151.1757812F, + 148.9296875F, 131.5390625F, 114.1484375F, 96.7578125F, + 79.3671875F, 61.9765625F, 44.5859375F, 27.1953125F, + 29.94140625F, 52.82421875F, 75.70703125F, 98.58984375F, + 121.4726562F, 144.3554688F, 167.2382812F, 190.1210938F, + 201.3671875F, 200.9765625F, 200.5859375F, 200.1953125F, + 199.8046875F, 199.4140625F, 199.0234375F, 198.6328125F, + 194.3085938F, 186.0507812F, 177.7929688F, 169.5351562F, + 161.2773438F, 153.0195312F, 144.7617188F, 136.5039062F, + 129.015625F, 122.296875F, 115.578125F, 108.859375F, + 102.140625F, 95.421875F, 88.703125F, 81.984375F, + 84.04296875F, 94.87890625F, 105.7148438F, 116.5507812F, + 127.3867188F, 138.2226562F, 149.0585938F, 159.8945312F, + 162.0351562F, 155.4804688F, 148.9257812F, 142.3710938F, + 135.8164062F, 129.2617188F, 122.7070312F, 116.1523438F, + 117.171875F, 125.765625F, 134.359375F, 142.953125F, + 151.546875F, 160.140625F, 168.734375F, 177.328125F, + 178.8046875F, 173.1640625F, 167.5234375F, 161.8828125F, + 156.2421875F, 150.6015625F, 144.9609375F, 139.3203125F, + 133.765625F, 128.296875F, 122.828125F, 117.359375F, + 111.890625F, 106.421875F, 100.953125F, 95.484375F, + 94.77734375F, 98.83203125F, 102.8867188F, 106.9414062F, + 110.9960938F, 115.0507812F, 119.1054688F, 123.1601562F, + 118.453125F, 104.984375F, 91.515625F, 78.046875F, + 64.578125F, 51.109375F, 37.640625F, 24.171875F, + 22.3671875F, 32.2265625F, 42.0859375F, 51.9453125F, + 61.8046875F, 71.6640625F, 81.5234375F, 91.3828125F, + 100.1054688F, 107.6914062F, 115.2773438F, 122.8632812F, + 130.4492188F, 138.0351562F, 145.6210938F, 153.2070312F, + 151.890625F, 141.671875F, 131.453125F, 121.234375F, + 111.015625F, 100.796875F, 90.578125F, 80.359375F, + 75.2421875F, 75.2265625F, 75.2109375F, 75.1953125F, + 75.1796875F, 75.1640625F, 75.1484375F, 75.1328125F, + 75.90234375F, 77.45703125F, 79.01171875F, 80.56640625F, + 82.12109375F, 83.67578125F, 85.23046875F, 86.78515625F, + 87.5625F, 87.5625F, 87.5625F, 87.5625F}, + {1.75F, 1.75F, 1.75F, 1.75F, + 1.8125F, 1.9375F, 2.0625F, 2.1875F, + 2.3125F, 2.4375F, 2.5625F, 2.6875F, + 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, + 10.8125F, 10.9375F, 11.0625F, 11.1875F, + 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 19.17578125F, 34.02734375F, 48.87890625F, 63.73046875F, + 78.58203125F, 93.43359375F, 108.2851562F, 123.1367188F, + 129.0546875F, 126.0390625F, 123.0234375F, 120.0078125F, + 116.9921875F, 113.9765625F, 110.9609375F, 107.9453125F, + 106.3125F, 106.0625F, 105.8125F, 105.5625F, + 105.3125F, 105.0625F, 104.8125F, 104.5625F, + 106.9296875F, 111.9140625F, 116.8984375F, 121.8828125F, + 126.8671875F, 131.8515625F, 136.8359375F, 141.8203125F, + 146.171875F, 149.890625F, 153.609375F, 157.328125F, + 161.046875F, 164.765625F, 168.484375F, 172.203125F, + 166.796875F, 152.265625F, 137.734375F, 123.203125F, + 108.671875F, 94.140625F, 79.609375F, 65.078125F, + 63.94140625F, 76.19921875F, 88.45703125F, 100.7148438F, + 112.9726562F, 125.2304688F, 137.4882812F, 149.7460938F, + 147.2265625F, 129.9296875F, 112.6328125F, 95.3359375F, + 78.0390625F, 60.7421875F, 43.4453125F, 26.1484375F, + 28.54296875F, 50.62890625F, 72.71484375F, 94.80078125F, + 116.8867188F, 138.9726562F, 161.0585938F, 183.1445312F, + 193.5390625F, 192.2421875F, 190.9453125F, 189.6484375F, + 188.3515625F, 187.0546875F, 185.7578125F, 184.4609375F, + 179.3320312F, 170.3710938F, 161.4101562F, 152.4492188F, + 143.4882812F, 134.5273438F, 125.5664062F, 116.6054688F, + 109.171875F, 103.265625F, 97.359375F, 91.453125F, + 85.546875F, 79.640625F, 73.734375F, 67.828125F, + 69.66015625F, 79.23046875F, 88.80078125F, 98.37109375F, + 107.9414062F, 117.5117188F, 127.0820312F, 136.6523438F, + 138.8242188F, 133.5976562F, 128.3710938F, 123.1445312F, + 117.9179688F, 112.6914062F, 107.4648438F, 102.2382812F, + 104.390625F, 113.921875F, 123.453125F, 132.984375F, + 142.515625F, 152.046875F, 161.578125F, 171.109375F, + 173.2265625F, 167.9296875F, 162.6328125F, 157.3359375F, + 152.0390625F, 146.7421875F, 141.4453125F, 136.1484375F, + 130.671875F, 125.015625F, 119.359375F, 113.703125F, + 108.046875F, 102.390625F, 96.734375F, 91.078125F, + 89.98828125F, 93.46484375F, 96.94140625F, 100.4179688F, + 103.8945312F, 107.3710938F, 110.8476562F, 114.3242188F, + 109.859375F, 97.453125F, 85.046875F, 72.640625F, + 60.234375F, 47.828125F, 35.421875F, 23.015625F, + 21.0390625F, 29.4921875F, 37.9453125F, 46.3984375F, + 54.8515625F, 63.3046875F, 71.7578125F, 80.2109375F, + 88.59765625F, 96.91796875F, 105.2382812F, 113.5585938F, + 121.8789062F, 130.1992188F, 138.5195312F, 146.8398438F, + 147.921875F, 141.765625F, 135.609375F, 129.453125F, + 123.296875F, 117.140625F, 110.984375F, 104.828125F, + 101.6640625F, 101.4921875F, 101.3203125F, 101.1484375F, + 100.9765625F, 100.8046875F, 100.6328125F, 100.4609375F, + 100.2382812F, 99.96484375F, 99.69140625F, 99.41796875F, + 99.14453125F, 98.87109375F, 98.59765625F, 98.32421875F, + 98.1875F, 98.1875F, 98.1875F, 98.1875F}, + {2.25F, 2.25F, 2.25F, 2.25F, + 2.3125F, 2.4375F, 2.5625F, 2.6875F, + 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, + 10.8125F, 10.9375F, 11.0625F, 11.1875F, + 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, + 20.51171875F, 37.03515625F, 53.55859375F, 70.08203125F, + 86.60546875F, 103.1289062F, 119.6523438F, 136.1757812F, + 141.1953125F, 134.7109375F, 128.2265625F, 121.7421875F, + 115.2578125F, 108.7734375F, 102.2890625F, 95.8046875F, + 93.3125F, 94.8125F, 96.3125F, 97.8125F, + 99.3125F, 100.8125F, 102.3125F, 103.8125F, + 107.6953125F, 113.9609375F, 120.2265625F, 126.4921875F, + 132.7578125F, 139.0234375F, 145.2890625F, 151.5546875F, + 154.953125F, 155.484375F, 156.015625F, 156.546875F, + 157.078125F, 157.609375F, 158.140625F, 158.671875F, + 152.828125F, 140.609375F, 128.390625F, 116.171875F, + 103.953125F, 91.734375F, 79.515625F, 67.296875F, + 66.99609375F, 78.61328125F, 90.23046875F, 101.8476562F, + 113.4648438F, 125.0820312F, 136.6992188F, 148.3164062F, + 145.5234375F, 128.3203125F, 111.1171875F, 93.9140625F, + 76.7109375F, 59.5078125F, 42.3046875F, 25.1015625F, + 27.14453125F, 48.43359375F, 69.72265625F, 91.01171875F, + 112.3007812F, 133.5898438F, 154.8789062F, 176.1679688F, + 185.7109375F, 183.5078125F, 181.3046875F, 179.1015625F, + 176.8984375F, 174.6953125F, 172.4921875F, 170.2890625F, + 164.3554688F, 154.6914062F, 145.0273438F, 135.3632812F, + 125.6992188F, 116.0351562F, 106.3710938F, 96.70703125F, + 89.328125F, 84.234375F, 79.140625F, 74.046875F, + 68.953125F, 63.859375F, 58.765625F, 53.671875F, + 55.27734375F, 63.58203125F, 71.88671875F, 80.19140625F, + 88.49609375F, 96.80078125F, 105.1054688F, 113.4101562F, + 115.6132812F, 111.7148438F, 107.8164062F, 103.9179688F, + 100.0195312F, 96.12109375F, 92.22265625F, 88.32421875F, + 91.609375F, 102.078125F, 112.546875F, 123.015625F, + 133.484375F, 143.953125F, 154.421875F, 164.890625F, + 167.6484375F, 162.6953125F, 157.7421875F, 152.7890625F, + 147.8359375F, 142.8828125F, 137.9296875F, 132.9765625F, + 127.578125F, 121.734375F, 115.890625F, 110.046875F, + 104.203125F, 98.359375F, 92.515625F, 86.671875F, + 85.19921875F, 88.09765625F, 90.99609375F, 93.89453125F, + 96.79296875F, 99.69140625F, 102.5898438F, 105.4882812F, + 101.265625F, 89.921875F, 78.578125F, 67.234375F, + 55.890625F, 44.546875F, 33.203125F, 21.859375F, + 19.7109375F, 26.7578125F, 33.8046875F, 40.8515625F, + 47.8984375F, 54.9453125F, 61.9921875F, 69.0390625F, + 77.08984375F, 86.14453125F, 95.19921875F, 104.2539062F, + 113.3085938F, 122.3632812F, 131.4179688F, 140.4726562F, + 143.953125F, 141.859375F, 139.765625F, 137.671875F, + 135.578125F, 133.484375F, 131.390625F, 129.296875F, + 128.0859375F, 127.7578125F, 127.4296875F, 127.1015625F, + 126.7734375F, 126.4453125F, 126.1171875F, 125.7890625F, + 124.5742188F, 122.4726562F, 120.3710938F, 118.2695312F, + 116.1679688F, 114.0664062F, 111.9648438F, 109.8632812F, + 108.8125F, 108.8125F, 108.8125F, 108.8125F}, + {2.75F, 2.75F, 2.75F, 2.75F, + 2.8125F, 2.9375F, 3.0625F, 3.1875F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, + 10.8125F, 10.9375F, 11.0625F, 11.1875F, + 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, + 12.3125F, 12.4375F, 12.5625F, 12.6875F, + 21.84765625F, 40.04296875F, 58.23828125F, 76.43359375F, + 94.62890625F, 112.8242188F, 131.0195312F, 149.2148438F, + 153.3359375F, 143.3828125F, 133.4296875F, 123.4765625F, + 113.5234375F, 103.5703125F, 93.6171875F, 83.6640625F, + 80.3125F, 83.5625F, 86.8125F, 90.0625F, + 93.3125F, 96.5625F, 99.8125F, 103.0625F, + 108.4609375F, 116.0078125F, 123.5546875F, 131.1015625F, + 138.6484375F, 146.1953125F, 153.7421875F, 161.2890625F, + 163.734375F, 161.078125F, 158.421875F, 155.765625F, + 153.109375F, 150.453125F, 147.796875F, 145.140625F, + 138.859375F, 128.953125F, 119.046875F, 109.140625F, + 99.234375F, 89.328125F, 79.421875F, 69.515625F, + 70.05078125F, 81.02734375F, 92.00390625F, 102.9804688F, + 113.9570312F, 124.9335938F, 135.9101562F, 146.8867188F, + 143.8203125F, 126.7109375F, 109.6015625F, 92.4921875F, + 75.3828125F, 58.2734375F, 41.1640625F, 24.0546875F, + 25.74609375F, 46.23828125F, 66.73046875F, 87.22265625F, + 107.7148438F, 128.2070312F, 148.6992188F, 169.1914062F, + 177.8828125F, 174.7734375F, 171.6640625F, 168.5546875F, + 165.4453125F, 162.3359375F, 159.2265625F, 156.1171875F, + 149.3789062F, 139.0117188F, 128.6445312F, 118.2773438F, + 107.9101562F, 97.54296875F, 87.17578125F, 76.80859375F, + 69.484375F, 65.203125F, 60.921875F, 56.640625F, + 52.359375F, 48.078125F, 43.796875F, 39.515625F, + 40.89453125F, 47.93359375F, 54.97265625F, 62.01171875F, + 69.05078125F, 76.08984375F, 83.12890625F, 90.16796875F, + 92.40234375F, 89.83203125F, 87.26171875F, 84.69140625F, + 82.12109375F, 79.55078125F, 76.98046875F, 74.41015625F, + 78.828125F, 90.234375F, 101.640625F, 113.046875F, + 124.453125F, 135.859375F, 147.265625F, 158.671875F, + 162.0703125F, 157.4609375F, 152.8515625F, 148.2421875F, + 143.6328125F, 139.0234375F, 134.4140625F, 129.8046875F, + 124.484375F, 118.453125F, 112.421875F, 106.390625F, + 100.359375F, 94.328125F, 88.296875F, 82.265625F, + 80.41015625F, 82.73046875F, 85.05078125F, 87.37109375F, + 89.69140625F, 92.01171875F, 94.33203125F, 96.65234375F, + 92.671875F, 82.390625F, 72.109375F, 61.828125F, + 51.546875F, 41.265625F, 30.984375F, 20.703125F, + 18.3828125F, 24.0234375F, 29.6640625F, 35.3046875F, + 40.9453125F, 46.5859375F, 52.2265625F, 57.8671875F, + 65.58203125F, 75.37109375F, 85.16015625F, 94.94921875F, + 104.7382812F, 114.5273438F, 124.3164062F, 134.1054688F, + 139.984375F, 141.953125F, 143.921875F, 145.890625F, + 147.859375F, 149.828125F, 151.796875F, 153.765625F, + 154.5078125F, 154.0234375F, 153.5390625F, 153.0546875F, + 152.5703125F, 152.0859375F, 151.6015625F, 151.1171875F, + 148.9101562F, 144.9804688F, 141.0507812F, 137.1210938F, + 133.1914062F, 129.2617188F, 125.3320312F, 121.4023438F, + 119.4375F, 119.4375F, 119.4375F, 119.4375F}, + {3.25F, 3.25F, 3.25F, 3.25F, + 3.3125F, 3.4375F, 3.5625F, 3.6875F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, + 10.8125F, 10.9375F, 11.0625F, 11.1875F, + 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, + 12.3125F, 12.4375F, 12.5625F, 12.6875F, + 12.8125F, 12.9375F, 13.0625F, 13.1875F, + 23.18359375F, 43.05078125F, 62.91796875F, 82.78515625F, + 102.6523438F, 122.5195312F, 142.3867188F, 162.2539062F, + 165.4765625F, 152.0546875F, 138.6328125F, 125.2109375F, + 111.7890625F, 98.3671875F, 84.9453125F, 71.5234375F, + 67.3125F, 72.3125F, 77.3125F, 82.3125F, + 87.3125F, 92.3125F, 97.3125F, 102.3125F, + 109.2265625F, 118.0546875F, 126.8828125F, 135.7109375F, + 144.5390625F, 153.3671875F, 162.1953125F, 171.0234375F, + 172.515625F, 166.671875F, 160.828125F, 154.984375F, + 149.140625F, 143.296875F, 137.453125F, 131.609375F, + 124.890625F, 117.296875F, 109.703125F, 102.109375F, + 94.515625F, 86.921875F, 79.328125F, 71.734375F, + 73.10546875F, 83.44140625F, 93.77734375F, 104.1132812F, + 114.4492188F, 124.7851562F, 135.1210938F, 145.4570312F, + 142.1171875F, 125.1015625F, 108.0859375F, 91.0703125F, + 74.0546875F, 57.0390625F, 40.0234375F, 23.0078125F, + 24.34765625F, 44.04296875F, 63.73828125F, 83.43359375F, + 103.1289062F, 122.8242188F, 142.5195312F, 162.2148438F, + 170.0546875F, 166.0390625F, 162.0234375F, 158.0078125F, + 153.9921875F, 149.9765625F, 145.9609375F, 141.9453125F, + 134.4023438F, 123.3320312F, 112.2617188F, 101.1914062F, + 90.12109375F, 79.05078125F, 67.98046875F, 56.91015625F, + 49.640625F, 46.171875F, 42.703125F, 39.234375F, + 35.765625F, 32.296875F, 28.828125F, 25.359375F, + 26.51171875F, 32.28515625F, 38.05859375F, 43.83203125F, + 49.60546875F, 55.37890625F, 61.15234375F, 66.92578125F, + 69.19140625F, 67.94921875F, 66.70703125F, 65.46484375F, + 64.22265625F, 62.98046875F, 61.73828125F, 60.49609375F, + 66.046875F, 78.390625F, 90.734375F, 103.078125F, + 115.421875F, 127.765625F, 140.109375F, 152.453125F, + 156.4921875F, 152.2265625F, 147.9609375F, 143.6953125F, + 139.4296875F, 135.1640625F, 130.8984375F, 126.6328125F, + 121.390625F, 115.171875F, 108.953125F, 102.734375F, + 96.515625F, 90.296875F, 84.078125F, 77.859375F, + 75.62109375F, 77.36328125F, 79.10546875F, 80.84765625F, + 82.58984375F, 84.33203125F, 86.07421875F, 87.81640625F, + 84.078125F, 74.859375F, 65.640625F, 56.421875F, + 47.203125F, 37.984375F, 28.765625F, 19.546875F, + 17.0546875F, 21.2890625F, 25.5234375F, 29.7578125F, + 33.9921875F, 38.2265625F, 42.4609375F, 46.6953125F, + 54.07421875F, 64.59765625F, 75.12109375F, 85.64453125F, + 96.16796875F, 106.6914062F, 117.2148438F, 127.7382812F, + 136.015625F, 142.046875F, 148.078125F, 154.109375F, + 160.140625F, 166.171875F, 172.203125F, 178.234375F, + 180.9296875F, 180.2890625F, 179.6484375F, 179.0078125F, + 178.3671875F, 177.7265625F, 177.0859375F, 176.4453125F, + 173.2460938F, 167.4882812F, 161.7304688F, 155.9726562F, + 150.2148438F, 144.4570312F, 138.6992188F, 132.9414062F, + 130.0625F, 130.0625F, 130.0625F, 130.0625F}, + {3.75F, 3.75F, 3.75F, 3.75F, + 3.8125F, 3.9375F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, + 4.8125F, 4.9375F, 5.0625F, 5.1875F, + 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, + 6.3125F, 6.4375F, 6.5625F, 6.6875F, + 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, + 7.8125F, 7.9375F, 8.0625F, 8.1875F, + 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, + 9.3125F, 9.4375F, 9.5625F, 9.6875F, + 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, + 10.8125F, 10.9375F, 11.0625F, 11.1875F, + 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, + 12.3125F, 12.4375F, 12.5625F, 12.6875F, + 12.8125F, 12.9375F, 13.0625F, 13.1875F, + 13.3125F, 13.4375F, 13.5625F, 13.6875F, + 24.51953125F, 46.05859375F, 67.59765625F, 89.13671875F, + 110.6757812F, 132.2148438F, 153.7539062F, 175.2929688F, + 177.6171875F, 160.7265625F, 143.8359375F, 126.9453125F, + 110.0546875F, 93.1640625F, 76.2734375F, 59.3828125F, + 54.3125F, 61.0625F, 67.8125F, 74.5625F, + 81.3125F, 88.0625F, 94.8125F, 101.5625F, + 109.9921875F, 120.1015625F, 130.2109375F, 140.3203125F, + 150.4296875F, 160.5390625F, 170.6484375F, 180.7578125F, + 181.296875F, 172.265625F, 163.234375F, 154.203125F, + 145.171875F, 136.140625F, 127.109375F, 118.078125F, + 110.921875F, 105.640625F, 100.359375F, 95.078125F, + 89.796875F, 84.515625F, 79.234375F, 73.953125F, + 76.16015625F, 85.85546875F, 95.55078125F, 105.2460938F, + 114.9414062F, 124.6367188F, 134.3320312F, 144.0273438F, + 140.4140625F, 123.4921875F, 106.5703125F, 89.6484375F, + 72.7265625F, 55.8046875F, 38.8828125F, 21.9609375F, + 22.94921875F, 41.84765625F, 60.74609375F, 79.64453125F, + 98.54296875F, 117.4414062F, 136.3398438F, 155.2382812F, + 162.2265625F, 157.3046875F, 152.3828125F, 147.4609375F, + 142.5390625F, 137.6171875F, 132.6953125F, 127.7734375F, + 119.4257812F, 107.6523438F, 95.87890625F, 84.10546875F, + 72.33203125F, 60.55859375F, 48.78515625F, 37.01171875F, + 29.796875F, 27.140625F, 24.484375F, 21.828125F, + 19.171875F, 16.515625F, 13.859375F, 11.203125F, + 12.12890625F, 16.63671875F, 21.14453125F, 25.65234375F, + 30.16015625F, 34.66796875F, 39.17578125F, 43.68359375F, + 45.98046875F, 46.06640625F, 46.15234375F, 46.23828125F, + 46.32421875F, 46.41015625F, 46.49609375F, 46.58203125F, + 53.265625F, 66.546875F, 79.828125F, 93.109375F, + 106.390625F, 119.671875F, 132.953125F, 146.234375F, + 150.9140625F, 146.9921875F, 143.0703125F, 139.1484375F, + 135.2265625F, 131.3046875F, 127.3828125F, 123.4609375F, + 118.296875F, 111.890625F, 105.484375F, 99.078125F, + 92.671875F, 86.265625F, 79.859375F, 73.453125F, + 70.83203125F, 71.99609375F, 73.16015625F, 74.32421875F, + 75.48828125F, 76.65234375F, 77.81640625F, 78.98046875F, + 75.484375F, 67.328125F, 59.171875F, 51.015625F, + 42.859375F, 34.703125F, 26.546875F, 18.390625F, + 15.7265625F, 18.5546875F, 21.3828125F, 24.2109375F, + 27.0390625F, 29.8671875F, 32.6953125F, 35.5234375F, + 42.56640625F, 53.82421875F, 65.08203125F, 76.33984375F, + 87.59765625F, 98.85546875F, 110.1132812F, 121.3710938F, + 132.046875F, 142.140625F, 152.234375F, 162.328125F, + 172.421875F, 182.515625F, 192.609375F, 202.703125F, + 207.3515625F, 206.5546875F, 205.7578125F, 204.9609375F, + 204.1640625F, 203.3671875F, 202.5703125F, 201.7734375F, + 197.5820312F, 189.9960938F, 182.4101562F, 174.8242188F, + 167.2382812F, 159.6523438F, 152.0664062F, 144.4804688F, + 140.6875F, 140.6875F, 140.6875F, 140.6875F}, + {4.0F, 4.0F, 4.0F, 4.0F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, 4.8125F, 4.9375F, + 5.0625F, 5.1875F, 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, 6.3125F, 6.4375F, + 6.5625F, 6.6875F, 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, 7.8125F, 7.9375F, + 8.0625F, 8.1875F, 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, 9.3125F, 9.4375F, + 9.5625F, 9.6875F, 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, 10.8125F, 10.9375F, + 11.0625F, 11.1875F, 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, 12.3125F, 12.4375F, + 12.5625F, 12.6875F, 12.8125F, 12.9375F, 13.0625F, 13.1875F, + 13.3125F, 13.4375F, 13.5625F, 13.6875F, 13.8125F, 13.9375F, + 25.1875F, 47.5625F, 69.9375F, 92.3125F, 114.6875F, 137.0625F, + 159.4375F, 181.8125F, 183.6875F, 165.0625F, 146.4375F, 127.8125F, + 109.1875F, 90.5625F, 71.9375F, 53.3125F, 47.8125F, 55.4375F, + 63.0625F, 70.6875F, 78.3125F, 85.9375F, 93.5625F, 101.1875F, + 110.375F, 121.125F, 131.875F, 142.625F, 153.375F, 164.125F, + 174.875F, 185.625F, 185.6875F, 175.0625F, 164.4375F, 153.8125F, + 143.1875F, 132.5625F, 121.9375F, 111.3125F, 103.9375F, 99.8125F, + 95.6875F, 91.5625F, 87.4375F, 83.3125F, 79.1875F, 75.0625F, + 77.6875F, 87.0625F, 96.4375F, 105.8125F, 115.1875F, 124.5625F, + 133.9375F, 143.3125F, 139.5625F, 122.6875F, 105.8125F, 88.9375F, + 72.0625F, 55.1875F, 38.3125F, 21.4375F, 22.25F, 40.75F, + 59.25F, 77.75F, 96.25F, 114.75F, 133.25F, 151.75F, + 158.3125F, 152.9375F, 147.5625F, 142.1875F, 136.8125F, 131.4375F, + 126.0625F, 120.6875F, 111.9375F, 99.8125F, 87.6875F, 75.5625F, + 63.4375F, 51.3125F, 39.1875F, 27.0625F, 19.875F, 17.625F, + 15.375F, 13.125F, 10.875F, 8.625F, 6.375F, 4.125F, + 4.9375F, 8.8125F, 12.6875F, 16.5625F, 20.4375F, 24.3125F, + 28.1875F, 32.0625F, 34.375F, 35.125F, 35.875F, 36.625F, + 37.375F, 38.125F, 38.875F, 39.625F, 46.875F, 60.625F, + 74.375F, 88.125F, 101.875F, 115.625F, 129.375F, 143.125F, + 148.125F, 144.375F, 140.625F, 136.875F, 133.125F, 129.375F, + 125.625F, 121.875F, 116.75F, 110.25F, 103.75F, 97.25F, + 90.75F, 84.25F, 77.75F, 71.25F, 68.4375F, 69.3125F, + 70.1875F, 71.0625F, 71.9375F, 72.8125F, 73.6875F, 74.5625F, + 71.1875F, 63.5625F, 55.9375F, 48.3125F, 40.6875F, 33.0625F, + 25.4375F, 17.8125F, 15.0625F, 17.1875F, 19.3125F, 21.4375F, + 23.5625F, 25.6875F, 27.8125F, 29.9375F, 36.8125F, 48.4375F, + 60.0625F, 71.6875F, 83.3125F, 94.9375F, 106.5625F, 118.1875F, + 130.0625F, 142.1875F, 154.3125F, 166.4375F, 178.5625F, 190.6875F, + 202.8125F, 214.9375F, 220.5625F, 219.6875F, 218.8125F, 217.9375F, + 217.0625F, 216.1875F, 215.3125F, 214.4375F, 209.75F, 201.25F, + 192.75F, 184.25F, 175.75F, 167.25F, 158.75F, 150.25F, + 146.0F, 146.0F, 146.0F, 146.0F}, + {4.0F, 4.0F, 4.0F, 4.0F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, 4.8125F, 4.9375F, + 5.0625F, 5.1875F, 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, 6.3125F, 6.4375F, + 6.5625F, 6.6875F, 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, 7.8125F, 7.9375F, + 8.0625F, 8.1875F, 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, 9.3125F, 9.4375F, + 9.5625F, 9.6875F, 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, 10.8125F, 10.9375F, + 11.0625F, 11.1875F, 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, 12.3125F, 12.4375F, + 12.5625F, 12.6875F, 12.8125F, 12.9375F, 13.0625F, 13.1875F, + 13.3125F, 13.4375F, 13.5625F, 13.6875F, 13.8125F, 13.9375F, + 25.1875F, 47.5625F, 69.9375F, 92.3125F, 114.6875F, 137.0625F, + 159.4375F, 181.8125F, 183.6875F, 165.0625F, 146.4375F, 127.8125F, + 109.1875F, 90.5625F, 71.9375F, 53.3125F, 47.8125F, 55.4375F, + 63.0625F, 70.6875F, 78.3125F, 85.9375F, 93.5625F, 101.1875F, + 110.375F, 121.125F, 131.875F, 142.625F, 153.375F, 164.125F, + 174.875F, 185.625F, 185.6875F, 175.0625F, 164.4375F, 153.8125F, + 143.1875F, 132.5625F, 121.9375F, 111.3125F, 103.9375F, 99.8125F, + 95.6875F, 91.5625F, 87.4375F, 83.3125F, 79.1875F, 75.0625F, + 77.6875F, 87.0625F, 96.4375F, 105.8125F, 115.1875F, 124.5625F, + 133.9375F, 143.3125F, 139.5625F, 122.6875F, 105.8125F, 88.9375F, + 72.0625F, 55.1875F, 38.3125F, 21.4375F, 22.25F, 40.75F, + 59.25F, 77.75F, 96.25F, 114.75F, 133.25F, 151.75F, + 158.3125F, 152.9375F, 147.5625F, 142.1875F, 136.8125F, 131.4375F, + 126.0625F, 120.6875F, 111.9375F, 99.8125F, 87.6875F, 75.5625F, + 63.4375F, 51.3125F, 39.1875F, 27.0625F, 19.875F, 17.625F, + 15.375F, 13.125F, 10.875F, 8.625F, 6.375F, 4.125F, + 4.9375F, 8.8125F, 12.6875F, 16.5625F, 20.4375F, 24.3125F, + 28.1875F, 32.0625F, 34.375F, 35.125F, 35.875F, 36.625F, + 37.375F, 38.125F, 38.875F, 39.625F, 46.875F, 60.625F, + 74.375F, 88.125F, 101.875F, 115.625F, 129.375F, 143.125F, + 148.125F, 144.375F, 140.625F, 136.875F, 133.125F, 129.375F, + 125.625F, 121.875F, 116.75F, 110.25F, 103.75F, 97.25F, + 90.75F, 84.25F, 77.75F, 71.25F, 68.4375F, 69.3125F, + 70.1875F, 71.0625F, 71.9375F, 72.8125F, 73.6875F, 74.5625F, + 71.1875F, 63.5625F, 55.9375F, 48.3125F, 40.6875F, 33.0625F, + 25.4375F, 17.8125F, 15.0625F, 17.1875F, 19.3125F, 21.4375F, + 23.5625F, 25.6875F, 27.8125F, 29.9375F, 36.8125F, 48.4375F, + 60.0625F, 71.6875F, 83.3125F, 94.9375F, 106.5625F, 118.1875F, + 130.0625F, 142.1875F, 154.3125F, 166.4375F, 178.5625F, 190.6875F, + 202.8125F, 214.9375F, 220.5625F, 219.6875F, 218.8125F, 217.9375F, + 217.0625F, 216.1875F, 215.3125F, 214.4375F, 209.75F, 201.25F, + 192.75F, 184.25F, 175.75F, 167.25F, 158.75F, 150.25F, + 146.0F, 146.0F, 146.0F, 146.0F}, + {4.0F, 4.0F, 4.0F, 4.0F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, 4.8125F, 4.9375F, + 5.0625F, 5.1875F, 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, 6.3125F, 6.4375F, + 6.5625F, 6.6875F, 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, 7.8125F, 7.9375F, + 8.0625F, 8.1875F, 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, 9.3125F, 9.4375F, + 9.5625F, 9.6875F, 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, 10.8125F, 10.9375F, + 11.0625F, 11.1875F, 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, 12.3125F, 12.4375F, + 12.5625F, 12.6875F, 12.8125F, 12.9375F, 13.0625F, 13.1875F, + 13.3125F, 13.4375F, 13.5625F, 13.6875F, 13.8125F, 13.9375F, + 25.1875F, 47.5625F, 69.9375F, 92.3125F, 114.6875F, 137.0625F, + 159.4375F, 181.8125F, 183.6875F, 165.0625F, 146.4375F, 127.8125F, + 109.1875F, 90.5625F, 71.9375F, 53.3125F, 47.8125F, 55.4375F, + 63.0625F, 70.6875F, 78.3125F, 85.9375F, 93.5625F, 101.1875F, + 110.375F, 121.125F, 131.875F, 142.625F, 153.375F, 164.125F, + 174.875F, 185.625F, 185.6875F, 175.0625F, 164.4375F, 153.8125F, + 143.1875F, 132.5625F, 121.9375F, 111.3125F, 103.9375F, 99.8125F, + 95.6875F, 91.5625F, 87.4375F, 83.3125F, 79.1875F, 75.0625F, + 77.6875F, 87.0625F, 96.4375F, 105.8125F, 115.1875F, 124.5625F, + 133.9375F, 143.3125F, 139.5625F, 122.6875F, 105.8125F, 88.9375F, + 72.0625F, 55.1875F, 38.3125F, 21.4375F, 22.25F, 40.75F, + 59.25F, 77.75F, 96.25F, 114.75F, 133.25F, 151.75F, + 158.3125F, 152.9375F, 147.5625F, 142.1875F, 136.8125F, 131.4375F, + 126.0625F, 120.6875F, 111.9375F, 99.8125F, 87.6875F, 75.5625F, + 63.4375F, 51.3125F, 39.1875F, 27.0625F, 19.875F, 17.625F, + 15.375F, 13.125F, 10.875F, 8.625F, 6.375F, 4.125F, + 4.9375F, 8.8125F, 12.6875F, 16.5625F, 20.4375F, 24.3125F, + 28.1875F, 32.0625F, 34.375F, 35.125F, 35.875F, 36.625F, + 37.375F, 38.125F, 38.875F, 39.625F, 46.875F, 60.625F, + 74.375F, 88.125F, 101.875F, 115.625F, 129.375F, 143.125F, + 148.125F, 144.375F, 140.625F, 136.875F, 133.125F, 129.375F, + 125.625F, 121.875F, 116.75F, 110.25F, 103.75F, 97.25F, + 90.75F, 84.25F, 77.75F, 71.25F, 68.4375F, 69.3125F, + 70.1875F, 71.0625F, 71.9375F, 72.8125F, 73.6875F, 74.5625F, + 71.1875F, 63.5625F, 55.9375F, 48.3125F, 40.6875F, 33.0625F, + 25.4375F, 17.8125F, 15.0625F, 17.1875F, 19.3125F, 21.4375F, + 23.5625F, 25.6875F, 27.8125F, 29.9375F, 36.8125F, 48.4375F, + 60.0625F, 71.6875F, 83.3125F, 94.9375F, 106.5625F, 118.1875F, + 130.0625F, 142.1875F, 154.3125F, 166.4375F, 178.5625F, 190.6875F, + 202.8125F, 214.9375F, 220.5625F, 219.6875F, 218.8125F, 217.9375F, + 217.0625F, 216.1875F, 215.3125F, 214.4375F, 209.75F, 201.25F, + 192.75F, 184.25F, 175.75F, 167.25F, 158.75F, 150.25F, + 146.0F, 146.0F, 146.0F, 146.0F}, + {4.0F, 4.0F, 4.0F, 4.0F, 4.0625F, 4.1875F, + 4.3125F, 4.4375F, 4.5625F, 4.6875F, 4.8125F, 4.9375F, + 5.0625F, 5.1875F, 5.3125F, 5.4375F, 5.5625F, 5.6875F, + 5.8125F, 5.9375F, 6.0625F, 6.1875F, 6.3125F, 6.4375F, + 6.5625F, 6.6875F, 6.8125F, 6.9375F, 7.0625F, 7.1875F, + 7.3125F, 7.4375F, 7.5625F, 7.6875F, 7.8125F, 7.9375F, + 8.0625F, 8.1875F, 8.3125F, 8.4375F, 8.5625F, 8.6875F, + 8.8125F, 8.9375F, 9.0625F, 9.1875F, 9.3125F, 9.4375F, + 9.5625F, 9.6875F, 9.8125F, 9.9375F, 10.0625F, 10.1875F, + 10.3125F, 10.4375F, 10.5625F, 10.6875F, 10.8125F, 10.9375F, + 11.0625F, 11.1875F, 11.3125F, 11.4375F, 11.5625F, 11.6875F, + 11.8125F, 11.9375F, 12.0625F, 12.1875F, 12.3125F, 12.4375F, + 12.5625F, 12.6875F, 12.8125F, 12.9375F, 13.0625F, 13.1875F, + 13.3125F, 13.4375F, 13.5625F, 13.6875F, 13.8125F, 13.9375F, + 25.1875F, 47.5625F, 69.9375F, 92.3125F, 114.6875F, 137.0625F, + 159.4375F, 181.8125F, 183.6875F, 165.0625F, 146.4375F, 127.8125F, + 109.1875F, 90.5625F, 71.9375F, 53.3125F, 47.8125F, 55.4375F, + 63.0625F, 70.6875F, 78.3125F, 85.9375F, 93.5625F, 101.1875F, + 110.375F, 121.125F, 131.875F, 142.625F, 153.375F, 164.125F, + 174.875F, 185.625F, 185.6875F, 175.0625F, 164.4375F, 153.8125F, + 143.1875F, 132.5625F, 121.9375F, 111.3125F, 103.9375F, 99.8125F, + 95.6875F, 91.5625F, 87.4375F, 83.3125F, 79.1875F, 75.0625F, + 77.6875F, 87.0625F, 96.4375F, 105.8125F, 115.1875F, 124.5625F, + 133.9375F, 143.3125F, 139.5625F, 122.6875F, 105.8125F, 88.9375F, + 72.0625F, 55.1875F, 38.3125F, 21.4375F, 22.25F, 40.75F, + 59.25F, 77.75F, 96.25F, 114.75F, 133.25F, 151.75F, + 158.3125F, 152.9375F, 147.5625F, 142.1875F, 136.8125F, 131.4375F, + 126.0625F, 120.6875F, 111.9375F, 99.8125F, 87.6875F, 75.5625F, + 63.4375F, 51.3125F, 39.1875F, 27.0625F, 19.875F, 17.625F, + 15.375F, 13.125F, 10.875F, 8.625F, 6.375F, 4.125F, + 4.9375F, 8.8125F, 12.6875F, 16.5625F, 20.4375F, 24.3125F, + 28.1875F, 32.0625F, 34.375F, 35.125F, 35.875F, 36.625F, + 37.375F, 38.125F, 38.875F, 39.625F, 46.875F, 60.625F, + 74.375F, 88.125F, 101.875F, 115.625F, 129.375F, 143.125F, + 148.125F, 144.375F, 140.625F, 136.875F, 133.125F, 129.375F, + 125.625F, 121.875F, 116.75F, 110.25F, 103.75F, 97.25F, + 90.75F, 84.25F, 77.75F, 71.25F, 68.4375F, 69.3125F, + 70.1875F, 71.0625F, 71.9375F, 72.8125F, 73.6875F, 74.5625F, + 71.1875F, 63.5625F, 55.9375F, 48.3125F, 40.6875F, 33.0625F, + 25.4375F, 17.8125F, 15.0625F, 17.1875F, 19.3125F, 21.4375F, + 23.5625F, 25.6875F, 27.8125F, 29.9375F, 36.8125F, 48.4375F, + 60.0625F, 71.6875F, 83.3125F, 94.9375F, 106.5625F, 118.1875F, + 130.0625F, 142.1875F, 154.3125F, 166.4375F, 178.5625F, 190.6875F, + 202.8125F, 214.9375F, 220.5625F, 219.6875F, 218.8125F, 217.9375F, + 217.0625F, 216.1875F, 215.3125F, 214.4375F, 209.75F, 201.25F, + 192.75F, 184.25F, 175.75F, 167.25F, 158.75F, 150.25F, + 146.0F, 146.0F, 146.0F, 146.0F}}}));