2
This file is part of TON Blockchain Library.
4
TON Blockchain Library is free software: you can redistribute it and/or modify
5
it under the terms of the GNU Lesser General Public License as published by
6
the Free Software Foundation, either version 2 of the License, or
7
(at your option) any later version.
9
TON Blockchain Library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public License
15
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
17
Copyright 2017-2020 Telegram Systems LLP
20
#include "LossSender.h"
22
#include "td/utils/logging.h"
25
#include <gsl/gsl_cdf.h>
33
// works for 1e-x, where x in {1..10}
34
double ndtri_fast(double p) {
36
return 6.361340902404;
39
return 5.997807015008;
42
return 5.612001244175;
45
return 5.199337582193;
48
return 4.753424308823;
51
return 4.264890793923;
54
return 3.719016485456;
57
return 3.090232306168;
60
return 2.326347874041;
62
return 1.281551565545;
66
LossSender::LossSender(double loss, double p) : loss_(loss), p_(p) {
72
//LOG(ERROR) << S_ << " " << ndtri(1 - p_);
73
//CHECK(fabs(S_ - ndtri(1 - p_)) < 1e-6);
76
int LossSender::send_n(int n) {
78
return send_n_exact(n);
80
return send_n_approx_nbd(n);
83
int LossSender::send_n_exact(int n) {
84
while ((int)res_.size() <= n) {
90
int LossSender::send_n_approx_norm(int n) {
91
double a = (1 - loss_) * (1 - loss_);
92
double b = loss_ * (loss_ - 1) * (2 * n + S_ * S_);
93
double c = loss_ * loss_ * n * n + S_ * S_ * n * loss_ * (loss_ - 1);
94
double x = ((-b + sqrt(b * b - 4 * a * c)) / (2 * a));
95
return (int)(x + n + 1);
98
int LossSender::send_n_approx_nbd(int n) {
100
auto mean = n * loss_ / (1 - loss_);
101
auto var = sqrt(mean / (1 - loss_));
102
auto min_k = static_cast<int>(mean + var);
103
auto max_k = min_k + static_cast<int>(var + 1) * 15;
104
while (min_k + 1 < max_k) {
105
int k = (min_k + max_k) / 2;
106
if (gsl_cdf_negative_binomial_P(k, 1 - loss_, n) > 1 - p_) {
114
return send_n_approx_norm(n);
117
int LossSender::send_n_approx_pd(int n) {
119
for (int k = 0;; k++) {
120
if (gsl_cdf_poisson_P(k, (n + k) * loss_) > 1 - p_) {
125
return send_n_approx_norm(n);
127
bool LossSender::has_good_approx() {
135
void LossSender::step() {
139
for (int j = n_; j >= 0; j--) {
140
v_[j + 1] += v_[j] * loss_;
141
v_[j] *= (1 - loss_);
144
while (res_i_ < n_ && v_[res_i_] < 1 - p_) {
147
auto left_ = n_ - res_i_;
148
if ((int)res_.size() == left_) {