View | Details | Raw Unified | Return to issue 75279
Collapse All | Expand All

(-)source_m100/core/inc/interpre.hxx (+1 lines)
Lines 701-706 Link Here
701
double GetLogGamma(double x);
701
double GetLogGamma(double x);
702
double GetBeta(double fAlpha, double fBeta);
702
double GetBeta(double fAlpha, double fBeta);
703
double GetLogBeta(double fAlpha, double fBeta);
703
double GetLogBeta(double fAlpha, double fBeta);
704
double GetBinomDistPMF(double x, double n, double p); //probability mass function
704
void ScLogGamma();
705
void ScLogGamma();
705
void ScGamma();
706
void ScGamma();
706
void ScPhi();
707
void ScPhi();
(-)source_m100/core/tool/interpr3.cxx (-140 / +112 lines)
Lines 949-965 Link Here
949
    const double fLogDblMin = log( ::std::numeric_limits<double>::min());
949
    const double fLogDblMin = log( ::std::numeric_limits<double>::min());
950
    double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5);
950
    double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5);
951
    double fLogX = log(fX);
951
    double fLogX = log(fX);
952
    double fAm1 = fA-1.0;
952
    double fAm1LogX = (fA-1.0) * fLogX;
953
    double fBm1 = fB-1.0;
953
    double fBm1LogY = (fB-1.0) * fLogY;
954
    double fLogBeta = GetLogBeta(fA,fB);
954
    double fLogBeta = GetLogBeta(fA,fB);
955
    // check whether parts over- or underflow
955
    // check whether parts over- or underflow
956
    if (   fAm1 * fLogX < fLogDblMax  && fAm1 * fLogX > fLogDblMin
956
    if (   fAm1LogX < fLogDblMax  && fAm1LogX > fLogDblMin
957
        && fBm1 * fLogY < fLogDblMax  && fBm1* fLogY > fLogDblMin
957
        && fBm1LogY < fLogDblMax  && fBm1LogY > fLogDblMin
958
        && fLogBeta < fLogDblMax      && fLogBeta > fLogDblMin )
958
        && fLogBeta < fLogDblMax  && fLogBeta > fLogDblMin
959
        && fAm1LogX + fBm1LogY < fLogDblMax && fAm1LogX + fBm1LogY > fLogDblMin)
959
        return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB);
960
        return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB);
960
    else // need logarithm;
961
    else // need logarithm;
961
        // might overflow as a whole, but seldom, not worth to pre-detect it
962
        // might overflow as a whole, but seldom, not worth to pre-detect it
962
        return exp((fA-1.0)*fLogX + (fB-1.0)* fLogY - fLogBeta);
963
        return exp( fAm1LogX + fBm1LogY - fLogBeta);
963
}
964
}
964
965
965
966
Lines 1226-1346 Link Here
1226
    }
1227
    }
1227
}
1228
}
1228
1229
1229
void ScInterpreter::ScB()
1230
1230
{
1231
double ScInterpreter::GetBinomDistPMF(double x, double n, double p)
1231
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" );
1232
// used in ScB and ScBinomDist
1232
    sal_uInt8 nParamCount = GetByte();
1233
// preconditions: 0.0 <= x <= n, 0.0 < p < 1.0;  x,n integral although double
1233
    if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
1234
        return ;
1235
    if (nParamCount == 3)
1236
    {
1237
        double x = ::rtl::math::approxFloor(GetDouble());
1238
        double p = GetDouble();
1239
        double n = ::rtl::math::approxFloor(GetDouble());
1240
        if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1241
            PushIllegalArgument();
1242
        else
1243
        {
1234
        {
1244
            double q = 1.0 - p;
1235
    double q = (0.5 - p) + 0.5;
1245
            double fFactor = pow(q, n);
1236
            double fFactor = pow(q, n);
1246
            if (fFactor == 0.0)
1237
    if (fFactor <=::std::numeric_limits<double>::min())
1247
            {
1238
            {
1248
                fFactor = pow(p, n);
1239
                fFactor = pow(p, n);
1249
                if (fFactor == 0.0)
1240
        if (fFactor <= ::std::numeric_limits<double>::min())
1250
                    PushNoValue();
1241
            return GetBetaDistPDF(p, x+1.0, n-x+1.0)/(n+1.0);
1251
                else
1242
                else
1252
                {
1243
                {
1253
                    sal_uLong max = (sal_uLong) (n - x);
1244
            sal_uInt32 max = static_cast<sal_uInt32>(n - x);
1254
                    for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
1245
            for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1255
                        fFactor *= (n-i)/(i+1)*q/p;
1246
                        fFactor *= (n-i)/(i+1)*q/p;
1256
                    PushDouble(fFactor);
1247
            return fFactor;
1257
                }
1248
                }
1258
            }
1249
            }
1259
            else
1250
            else
1260
            {
1251
            {
1261
                sal_uLong max = (sal_uLong) x;
1252
        sal_uInt32 max = static_cast<sal_uInt32>(x);
1262
                for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
1253
        for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1263
                    fFactor *= (n-i)/(i+1)*p/q;
1254
                    fFactor *= (n-i)/(i+1)*p/q;
1264
                PushDouble(fFactor);
1255
        return fFactor;
1265
            }
1266
        }
1256
        }
1267
    }
1257
    }
1268
    else if (nParamCount == 4)
1258
1269
    {
1259
double lcl_GetBinomDistRange(double n, double xs,double xe,
1270
        double xe = GetDouble();
1260
            double fFactor /* q^n */, double p, double q)
1271
        double xs = GetDouble();
1261
//preconditions: 0.0 <= xs < xe <= n; xs,xe,n integral although double
1272
        double p = GetDouble();
1273
        double n = GetDouble();
1274
//                                          alter Stand 300-SC
1275
//      if ((xs < n) && (xe < n) && (p < 1.0))
1276
//      {
1277
//          double Varianz = sqrt(n * p * (1.0 - p));
1278
//          xs = fabs(xs - (n * p /* / 2.0 STE */ ));
1279
//          xe = fabs(xe - (n * p /* / 2.0 STE */ ));
1280
//// STE        double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz);
1281
//          double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz));
1282
//          PushDouble(nVal);
1283
//      }
1284
        bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n);
1285
        if ( bIsValidX && 0.0 < p && p < 1.0 )
1286
        {
1287
            double q = 1.0 - p;
1288
            double fFactor = pow(q, n);
1289
            if (fFactor == 0.0)
1290
            {
1291
                fFactor = pow(p, n);
1292
                if (fFactor == 0.0)
1293
                    PushNoValue();
1294
                else
1295
                {
1262
                {
1296
                    double fSum = 0.0;
1263
    sal_uInt32 i;
1297
                    sal_uLong max;
1264
    double fSum;
1298
                    if (xe < (sal_uLong) n)
1265
    // skip summands index 0 to xs-1, start sum with index xs
1299
                        max = (sal_uLong) (n-xe)-1;
1266
    sal_uInt32 nXs = static_cast<sal_uInt32>( xs );
1300
                    else
1267
    for (i = 1; i <= nXs && fFactor > 0.0; i++)
1301
                        max = 0;
1268
        fFactor *= (n-i+1)/i * p/q;
1302
                    sal_uLong i;
1269
    fSum = fFactor; // Summand xs
1303
                    for (i = 0; i < max && fFactor > 0.0; i++)
1270
    sal_uInt32 nXe = static_cast<sal_uInt32>(xe);
1304
                        fFactor *= (n-i)/(i+1)*q/p;
1271
    for (i = nXs+1; i <= nXe && fFactor > 0.0; i++)
1305
                    if (xs < (sal_uLong) n)
1306
                        max = (sal_uLong) (n-xs);
1307
                    else
1308
                        fSum = fFactor;
1309
                    for (; i < max && fFactor > 0.0; i++)
1310
                    {
1272
                    {
1311
                        fFactor *= (n-i)/(i+1)*q/p;
1273
        fFactor *= (n-i+1)/i * p/q;
1312
                        fSum += fFactor;
1274
                        fSum += fFactor;
1313
                    }
1275
                    }
1314
                    PushDouble(fSum);
1276
    return (fSum>1.0) ? 1.0 : fSum;
1315
                }
1277
                }
1278
1279
void ScInterpreter::ScB()
1280
{
1281
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" );
1282
    sal_uInt8 nParamCount = GetByte();
1283
    if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
1284
        return ;
1285
    if (nParamCount == 3)   // mass function
1286
    {
1287
        double x = ::rtl::math::approxFloor(GetDouble());
1288
        double p = GetDouble();
1289
        double n = ::rtl::math::approxFloor(GetDouble());
1290
        if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1291
            PushIllegalArgument();
1292
        else
1293
            if (p == 0.0)
1294
                PushDouble( (x == 0.0) ? 1.0 : 0.0 );
1295
            else
1296
                if ( p == 1.0)
1297
                    PushDouble( (x == n) ? 1.0 : 0.0);
1298
                else
1299
                    PushDouble(GetBinomDistPMF(x,n,p));
1316
            }
1300
            }
1317
            else
1301
            else
1302
    {   // nParamCount == 4
1303
        double xe = ::rtl::math::approxFloor(GetDouble());
1304
        double xs = ::rtl::math::approxFloor(GetDouble());
1305
        double p = GetDouble();
1306
        double n = ::rtl::math::approxFloor(GetDouble());
1307
        double q = (0.5 - p) + 0.5;
1308
        bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n);
1309
        if ( bIsValidX && 0.0 < p && p < 1.0)
1318
            {
1310
            {
1319
                sal_uLong max;
1311
            if (xs == xe)       // mass function
1320
                double fSum;
1312
                PushDouble(GetBinomDistPMF(xs,n,p));
1321
                if ( (sal_uLong) xs == 0)
1313
            else
1322
                {
1314
                {
1323
                    fSum = fFactor;
1315
                double fFactor = pow(q, n);
1324
                    max = 0;
1316
                if (fFactor > ::std::numeric_limits<double>::min())
1325
                }
1317
                    PushDouble(lcl_GetBinomDistRange(n,xs,xe,fFactor,p,q));
1326
                else
1318
                else
1327
                {
1319
                {
1328
                    max = (sal_uLong) xs-1;
1320
                    fFactor = pow(p, n);
1329
                    fSum = 0.0;
1321
                    if (fFactor > ::std::numeric_limits<double>::min())
1322
                    {
1323
                    // sum from j=xs to xe {(n choose j) * p^j * q^(n-j)}
1324
                    // = sum from i = n-xe to n-xs { (n choose i) * q^i * p^(n-i)}
1325
                        PushDouble(lcl_GetBinomDistRange(n,n-xe,n-xs,fFactor,q,p));
1330
                }
1326
                }
1331
                sal_uLong i;
1332
                for (i = 0; i < max && fFactor > 0.0; i++)
1333
                    fFactor *= (n-i)/(i+1)*p/q;
1334
                if ((sal_uLong)xe == 0)                     // beide 0
1335
                    fSum = fFactor;
1336
                else
1327
                else
1337
                    max = (sal_uLong) xe;
1328
                        PushDouble(GetBetaDist(q,n-xe,xe+1.0)-GetBetaDist(q,n-xs+1,xs) );
1338
                for (; i < max && fFactor > 0.0; i++)
1339
                {
1340
                    fFactor *= (n-i)/(i+1)*p/q;
1341
                    fSum += fFactor;
1342
                }
1329
                }
1343
                PushDouble(fSum);
1344
            }
1330
            }
1345
        }
1331
        }
1346
        else
1332
        else
Lines 1365-1441 Link Here
1365
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBinomDist" );
1351
    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBinomDist" );
1366
    if ( MustHaveParamCount( GetByte(), 4 ) )
1352
    if ( MustHaveParamCount( GetByte(), 4 ) )
1367
    {
1353
    {
1368
        double kum    = GetDouble();                    // 0 oder 1
1354
        bool bIsCum   = GetBool();     // false=mass function; true=cumulative
1369
        double p      = GetDouble();                    // p
1355
        double p      = GetDouble();
1370
        double n      = ::rtl::math::approxFloor(GetDouble());              // n
1356
        double n      = ::rtl::math::approxFloor(GetDouble());
1371
        double x      = ::rtl::math::approxFloor(GetDouble());              // x
1357
        double x      = ::rtl::math::approxFloor(GetDouble());
1372
        double fFactor, q, fSum;
1358
        double q = (0.5 - p) + 0.5;           // get one bit more for p near 1.0
1359
        double fFactor, fSum;
1373
        if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1360
        if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0)
1374
            PushIllegalArgument();
1375
        else if (kum == 0.0)                        // Dichte
1376
        {
1361
        {
1377
            q = 1.0 - p;
1362
            PushIllegalArgument();
1378
            fFactor = pow(q, n);
1363
            return;
1379
            if (fFactor == 0.0)
1380
            {
1381
                fFactor = pow(p, n);
1382
                if (fFactor == 0.0)
1383
                    PushNoValue();
1384
                else
1385
                {
1386
                    sal_uLong max = (sal_uLong) (n - x);
1387
                    for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
1388
                        fFactor *= (n-i)/(i+1)*q/p;
1389
                    PushDouble(fFactor);
1390
                }
1391
            }
1364
            }
1392
            else
1365
        if ( p == 0.0)
1393
            {
1366
            {
1394
                sal_uLong max = (sal_uLong) x;
1367
            PushDouble( (x==0.0 || bIsCum) ? 1.0 : 0.0 );
1395
                for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
1368
            return;
1396
                    fFactor *= (n-i)/(i+1)*p/q;
1397
                PushDouble(fFactor);
1398
            }
1369
            }
1370
        if ( p == 1.0)
1371
        {
1372
            PushDouble( (x==n) ? 1.0 : 0.0);
1373
            return;
1399
        }
1374
        }
1400
        else                                        // Verteilung
1375
        if (!bIsCum)
1376
            PushDouble( GetBinomDistPMF(x,n,p));
1377
        else
1401
        {
1378
        {
1402
            if (n == x)
1379
            if (x == n)
1403
                PushDouble(1.0);
1380
                PushDouble(1.0);
1404
            else
1381
            else
1405
            {
1382
            {
1406
                q = 1.0 - p;
1407
                fFactor = pow(q, n);
1383
                fFactor = pow(q, n);
1408
                if (fFactor == 0.0)
1384
                if (x == 0.0)
1385
                    PushDouble(fFactor);
1386
                else
1387
                    if (fFactor <= ::std::numeric_limits<double>::min())
1409
                {
1388
                {
1410
                    fFactor = pow(p, n);
1389
                    fFactor = pow(p, n);
1411
                    if (fFactor == 0.0)
1390
                        if (fFactor <= ::std::numeric_limits<double>::min())
1412
                        PushNoValue();
1391
                            PushDouble(GetBetaDist(q,n-x,x+1.0));
1413
                    else
1392
                    else
1414
                    {
1393
                    {
1394
                            if (fFactor > fMachEps)
1395
                            {
1415
                        fSum = 1.0 - fFactor;
1396
                        fSum = 1.0 - fFactor;
1416
                        sal_uLong max = (sal_uLong) (n - x) - 1;
1397
                                sal_uInt32 max = static_cast<sal_uInt32> (n - x) - 1;
1417
                        for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
1398
                                for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++)
1418
                        {
1399
                        {
1419
                            fFactor *= (n-i)/(i+1)*q/p;
1400
                            fFactor *= (n-i)/(i+1)*q/p;
1420
                            fSum -= fFactor;
1401
                            fSum -= fFactor;
1421
                        }
1402
                        }
1422
                        if (fSum < 0.0)
1403
                                PushDouble( (fSum < 0.0) ? 0.0 : fSum );
1423
                            PushDouble(0.0);
1424
                        else
1425
                            PushDouble(fSum);
1426
                    }
1427
                }
1404
                }
1428
                else
1405
                else
1429
                {
1406
                                PushDouble(lcl_GetBinomDistRange(n,n-x,n,fFactor,q,p));
1430
                    fSum = fFactor;
1431
                    sal_uLong max = (sal_uLong) x;
1432
                    for (sal_uLong i = 0; i < max && fFactor > 0.0; i++)
1433
                    {
1434
                        fFactor *= (n-i)/(i+1)*p/q;
1435
                        fSum += fFactor;
1436
                    }
1407
                    }
1437
                    PushDouble(fSum);
1438
                }
1408
                }
1409
                    else
1410
                        PushDouble( lcl_GetBinomDistRange(n,0.0,x,fFactor,p,q)) ;
1439
            }
1411
            }
1440
        }
1412
        }
1441
    }
1413
    }

Return to issue 75279