| // Distributed under 3-clause BSD license with permission from the author, |
| // see https://lists.debian.org/debian-legal/2004/12/msg00295.html |
| // |
| // Cephes Math Library Release 2.8: June, 2000 |
| // |
| // Copyright 1984, 1995, 2000 by Stephen L. Moshier |
| // |
| // This software is derived from the Cephes Math Library and is |
| // incorporated herein by permission of the author. |
| // |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // * Neither the name of the <organization> nor the |
| // names of its contributors may be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY |
| // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| // DAMAGE. |
| // |
| // Note: The file inverse_gaussian_cdf.cc is a rewrite of the implementation |
| // of the ndtri function in the cephes library. It is not a copy; modification |
| // was permitted by the author under the above license. The original file can be |
| // found here: https://netlib.org/cephes/doubldoc.html#ndtri |
| #include "third_party/cephes/inverse_gaussian_cdf.h" |
| |
| #include <cstdlib> |
| #include <limits> |
| |
| #include "gtest/gtest.h" |
| |
| namespace differential_privacy::third_party::cephes { |
| namespace { |
| |
| TEST(InverseCdfStandardGaussianTest, InputZeroReturnsNagativeInfinity) { |
| EXPECT_EQ(InverseCdfStandardGaussian(0.0), |
| -std::numeric_limits<double>::infinity()); |
| } |
| |
| TEST(InverseCdfStandardGaussianTest, InputOneReturnsInfinity) { |
| EXPECT_EQ(InverseCdfStandardGaussian(1.0), |
| std::numeric_limits<double>::infinity()); |
| } |
| |
| TEST(InverseCdfStandardGaussianTest, VerifiesThatMedianOfGaussianIsZero) { |
| EXPECT_NEAR(InverseCdfStandardGaussian(0.5), 0, 1E-15); |
| } |
| |
| struct InputOutput { |
| double input; |
| double expected_output; |
| }; |
| |
| using InverseCdfStandardGaussianIoTest = ::testing::TestWithParam<InputOutput>; |
| |
| TEST_P(InverseCdfStandardGaussianIoTest, RelativeAccuracy) { |
| const InputOutput& test_case = GetParam(); |
| |
| double output = InverseCdfStandardGaussian(test_case.input); |
| double relative_accuracy = std::abs((output - test_case.expected_output) / |
| test_case.expected_output); |
| |
| EXPECT_NEAR(0.0, relative_accuracy, 1e-15); |
| } |
| |
| // Listing a number of correct input/output pairs. |
| // The values were generated by the following python code: |
| // |
| // from scipy.stats import norm |
| // from numpy.random import uniform |
| // |
| // numbers_per_order = 2 |
| // |
| // # p close to 1, st. 1-p is of order 10**(-i) |
| // # Due to rounding errors, this has limitations |
| // for i in range(1,14): |
| // for j in range(numbers_per_order): |
| // rand = uniform(1-10**(-i), 1) |
| // print("{%.18e, %.18f}," % (rand, norm.ppf(rand))) |
| // |
| // # p close to 0, st. p is of order 10**(-i) |
| // for i in [0, 1, 2, 4, 8, 15, 16, 17, 32, 64, 128, 256, 300]: |
| // for j in range(numbers_per_order): |
| // rand = uniform(0.1, 1) * 10**(-i) |
| // print("{%.18e, %.18f}," % (rand, norm.ppf(rand))) |
| INSTANTIATE_TEST_SUITE_P( |
| RelativeAccuracyTest, InverseCdfStandardGaussianIoTest, |
| testing::ValuesIn<InputOutput>({ |
| {9.590875421333870943e-01, 1.740194245526870631}, |
| {9.204728130878864212e-01, 1.408259059429154192}, |
| {9.987822916403579221e-01, 3.031252275870897073}, |
| {9.925605599510384236e-01, 2.435313800480054969}, |
| {9.990447702229799942e-01, 3.103810031034545780}, |
| {9.996763629885648816e-01, 3.410990265746212557}, |
| {9.999886033679458164e-01, 4.235609454156513465}, |
| {9.999760495761819135e-01, 4.065639908388418711}, |
| {9.999918285209185020e-01, 4.309763019113548310}, |
| {9.999949297010878313e-01, 4.414153527077065320}, |
| {9.999995741498048929e-01, 4.923131819830989464}, |
| {9.999997043019083209e-01, 4.994005806628707411}, |
| {9.999999930150607064e-01, 5.673757581075118850}, |
| {9.999999627780953304e-01, 5.380101608071190533}, |
| {9.999999977551378150e-01, 5.865059216395640540}, |
| {9.999999987822485448e-01, 5.965724924667977547}, |
| {9.999999996778887734e-01, 6.179212230118906746}, |
| {9.999999995927016938e-01, 6.142056907043477842}, |
| {9.999999999050942501e-01, 6.369365733005997399}, |
| {9.999999999612441126e-01, 6.505351784059330456}, |
| {9.999999999965828446e-01, 6.861077421111833274}, |
| {9.999999999911421966e-01, 6.723709001398219698}, |
| {9.999999999990811794e-01, 7.046280136673924055}, |
| {9.999999999995440314e-01, 7.143183551114592689}, |
| {9.999999999999484857e-01, 7.436960043545139065}, |
| {9.999999999999442668e-01, 7.426550452501929911}, |
| {7.078202134622706421e-01, 0.547027887498922949}, |
| {3.389657500740557161e-01, -0.415287432523317290}, |
| {5.957715702260371615e-02, -1.558333067730558463}, |
| {7.814884269185563836e-02, -1.417633872953655949}, |
| {7.031239497917323583e-03, -2.455663440450241986}, |
| {1.539105641403513232e-03, -2.959817704299271046}, |
| {4.308036802518321198e-05, -3.926584208482659655}, |
| {4.792417534760087735e-05, -3.900868137755500342}, |
| {4.463560376039031862e-09, -5.749947420065786297}, |
| {4.134037552039715277e-09, -5.762900076062255295}, |
| {4.483536530421512750e-16, -8.040229004994209561}, |
| {3.339983254697393151e-16, -8.076230307018560595}, |
| {6.215336569124182823e-17, -8.278911061075142186}, |
| {9.601065568608536918e-17, -8.226962019547366722}, |
| {6.991559520245878977e-18, -8.535267778973684827}, |
| {7.798272601053520958e-18, -8.522633695927112285}, |
| {9.753826112572825312e-33, -11.858220714899207593}, |
| {7.239945717749332110e-33, -11.883153923605899394}, |
| {3.081878658827924595e-65, -17.016810944246216764}, |
| {5.854299805089005594e-65, -16.979192464465175050}, |
| {8.217571054262086351e-129, -24.117363860470103276}, |
| {5.940660698416777152e-129, -24.130790266655189669}, |
| {7.104594771285924014e-257, -34.215527373144254852}, |
| {5.222691495369919695e-257, -34.224512368673167373}, |
| {9.255861729918001973e-301, -37.049182013454569073}, |
| {5.918562407887116857e-301, -37.061240736056291212}, |
| })); |
| |
| } // namespace |
| } // namespace differential_privacy::third_party::cephes |