Statistics
| Branch: | Revision:

root / src / sim / nedfunctions.cc @ e26d3d25

History | View | Annotate | Download (22 KB)

1 01873262 Georg Kunz
//=========================================================================
2
//  NEDFUNCTIONS.CC - part of
3
//
4
//                    OMNeT++/OMNEST
5
//             Discrete System Simulation in C++
6
//
7
//=========================================================================
8
9
/*--------------------------------------------------------------*
10
  Copyright (C) 1992-2008 Andras Varga
11
  Copyright (C) 2006-2008 OpenSim Ltd.
12

13
  This file is distributed WITHOUT ANY WARRANTY. See the file
14
  `license' for details on this and other legal matters.
15
*--------------------------------------------------------------*/
16
17
#include <math.h>
18
#include <string.h>
19
#include "distrib.h"
20
#include "cmathfunction.h"
21
#include "cnedfunction.h"
22
#include "cexception.h"
23
#include "cstringtokenizer.h"
24
#include "unitconversion.h"
25
#include "stringutil.h"
26
#include "stringpool.h"
27
#include "opp_ctype.h"
28
#include "cconfiguration.h"
29
30
USING_NAMESPACE
31
32
//FIXME cDynamicExpression to add function name to exceptions thrown from functions
33
34
void nedfunctions_dummy() {} //see util.cc
35
36
typedef cDynamicExpression::Value Value;  // abbreviation for local use
37
38
#define DEF(FUNCTION, SIGNATURE, CATEGORY, DESCRIPTION, BODY) \
39
    static Value FUNCTION(cComponent *context, Value argv[], int argc) {BODY} \
40
    Define_NED_Function2(FUNCTION, SIGNATURE, CATEGORY, DESCRIPTION);
41
42
43
//
44
// NED math.h functions
45
//
46
47
Define_Function3(acos, 1,  "math", "Trigonometric function; see standard C function of the same name")
48
Define_Function3(asin, 1,  "math", "Trigonometric function; see standard C function of the same name")
49
Define_Function3(atan, 1,  "math", "Trigonometric function; see standard C function of the same name")
50
Define_Function3(atan2, 2, "math", "Trigonometric function; see standard C function of the same name")
51
52
Define_Function3(sin, 1,   "math", "Trigonometric function; see standard C function of the same name")
53
Define_Function3(cos, 1,   "math", "Trigonometric function; see standard C function of the same name")
54
Define_Function3(tan, 1,   "math", "Trigonometric function; see standard C function of the same name")
55
56
Define_Function3(ceil, 1,  "math", "Rounds down; see standard C function of the same name")
57
Define_Function3(floor, 1, "math", "Rounds up; see standard C function of the same name")
58
59
Define_Function3(exp, 1,   "math", "Exponential; see standard C function of the same name")
60
Define_Function3(pow, 2,   "math", "Power; see standard C function of the same name")
61
Define_Function3(sqrt, 1,  "math", "Square root; see standard C function of the same name")
62
63
Define_Function3(hypot, 2, "math", "Length of the hypotenuse; see standard C function of the same name")
64
65
Define_Function3(log, 1,   "math", "Natural logarithm; see standard C function of the same name")
66
Define_Function3(log10, 1, "math", "Base-10 logarithm; see standard C function of the same name")
67
68
69
DEF(nedf_fabs,
70
    "quantity fabs(quantity x)",
71
    "math",
72
    "Returns the absolute value of the quantity.",
73
{
74
    argv[0].dbl = fabs(argv[0].dbl);  // preserve unit
75
    return argv[0];
76
})
77
78
DEF(nedf_fmod,
79
    "quantity fmod(quantity x, quantity y)",
80
    "math",
81
    "Returns the floating-point remainder of x/y; unit conversion takes place if needed.",
82
{
83
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
84
    argv[0].dbl = fmod(argv[0].dbl, argv1converted);
85
    return argv[0];
86
})
87
88
DEF(nedf_min,
89
    "quantity min(quantity a, quantity b)",
90
    "math",
91
    "Returns the smaller one of the two quantities; unit conversion takes place if needed.",
92
{
93
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
94
    return argv[0].dbl < argv1converted ? argv[0] : argv[1];
95
})
96
97
DEF(nedf_max,
98
    "quantity max(quantity a, quantity b)",
99
    "math",
100
    "Returns the greater one of the two quantities; unit conversion takes place if needed.",
101
{
102
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
103
    return argv[0].dbl < argv1converted ? argv[1] : argv[0];
104
})
105
106
107
//
108
// Unit handling
109
//
110
111
static CommonStringPool stringPool; // non-refcounted
112
113
DEF(nedf_dropUnit,
114
    "double dropUnit(quantity x)",
115
    "units",
116
    "Removes the unit of measurement from quantity x.",
117
{
118
    argv[0].dblunit = NULL;
119
    return argv[0];
120
})
121
122
DEF(nedf_replaceUnit,
123
    "quantity replaceUnit(quantity x, string unit)",
124
    "units",
125
    "Replaces the unit of x with the given unit.",
126
{
127
    argv[0].dblunit = stringPool.get(argv[1].s.c_str());
128
    return argv[0];
129
})
130
131
DEF(nedf_convertUnit,
132
    "quantity convertUnit(quantity x, string unit)",
133
    "units",
134
    "Converts x to the given unit.",
135
{
136
    const char *newUnit = stringPool.get(argv[1].s.c_str());
137
    argv[0].dbl = UnitConversion::convertUnit(argv[0].dbl, argv[0].dblunit, newUnit);
138
    argv[0].dblunit = newUnit;
139
    return argv[0];
140
})
141
142
DEF(nedf_unitOf,
143
    "string unitOf(quantity x)",
144
    "units",
145
    "Returns the unit of the given quantity.",
146
{
147
    return argv[0].dblunit;
148
})
149
150
151
//
152
// String manipulation functions.
153
//
154
155
DEF(nedf_length,
156
    "long length(string s)",
157
    "strings",
158
    "Returns the length of the string",
159
{
160
    return (long)argv[0].s.size();
161
})
162
163
DEF(nedf_contains,
164
    "bool contains(string s, string substr)",
165
    "strings",
166
    "Returns true if string s contains substr as substring",
167
{
168
    return argv[0].s.find(argv[1].s) != std::string::npos;
169
})
170
171
DEF(nedf_substring,
172
    "string substring(string s, long pos, long len?)",
173
    "strings",
174
    "Return the substring of s starting at the given position, either to the end of the string or maximum len characters",
175
{
176
    int size = argv[0].s.size();
177
    int index = (int)argv[1].dbl;
178
    int length = argc==3 ? (int)argv[2].dbl : size-index;
179
180
    if (index < 0 || index > size)
181
        throw cRuntimeError("substring(): index out of bounds");
182
    if (length < 0)
183
        throw cRuntimeError("substring(): length is negative");
184
    return argv[0].s.substr(index, length);
185
})
186
187
DEF(nedf_substringBefore,
188
    "string substringBefore(string s, string substr)",
189
    "strings",
190
    "Returns the substring of s before the first occurrence of substr, or the empty string if s does not contain substr.",
191
{
192
    size_t pos = argv[0].s.find(argv[1].s);
193
    return pos==std::string::npos ? "" : argv[0].s.substr(0,pos);
194
})
195
196
DEF(nedf_substringAfter,
197
    "string substringAfter(string s, string substr)",
198
    "strings",
199
    "Returns the substring of s after the first occurrence of substr, or the empty string if s does not contain substr.",
200
{
201
    size_t pos = argv[0].s.find(argv[1].s);
202
    return pos==std::string::npos ? "" : argv[0].s.substr(pos+argv[1].s.size());
203
})
204
205
DEF(nedf_substringBeforeLast,
206
    "string substringBeforeLast(string s, string substr)",
207
    "strings",
208
    "Returns the substring of s before the last occurrence of substr, or the empty string if s does not contain substr.",
209
{
210
    size_t pos = argv[0].s.rfind(argv[1].s);
211
    return pos==std::string::npos ? "" : argv[0].s.substr(0,pos);
212
})
213
214
DEF(nedf_substringAfterLast,
215
    "string substringAfterLast(string s, string substr)",
216
    "strings",
217
    "Returns the substring of s after the last occurrence of substr, or the empty string if s does not contain substr.",
218
{
219
    size_t pos = argv[0].s.rfind(argv[1].s);
220
    return pos==std::string::npos ? "" : argv[0].s.substr(pos+argv[1].s.size());
221
})
222
223
DEF(nedf_startsWith,
224
    "bool startsWith(string s, string substr)",
225
    "strings",
226
    "Returns true if s begins with the substring substr.",
227
{
228
    return argv[0].s.find(argv[1].s) == 0;
229
})
230
231
DEF(nedf_endsWith,
232
    "bool endsWith(string s, string substr)",
233
    "strings",
234
    "Returns true if s ends with the substring substr.",
235
{
236
    return argv[0].s.rfind(argv[1].s) == argv[0].s.size() - argv[1].s.size();
237
})
238
239
DEF(nedf_tail,
240
    "string tail(string s, long len)",
241
    "strings",
242
    "Returns the last len character of s, or the full s if it is shorter than len characters.",
243
{
244
    int length = (int)argv[1].dbl;
245
    if (length < 0)
246
        throw cRuntimeError("tail(): length is negative");
247
    int size = (int) argv[0].s.size();
248
    return argv[0].s.substr(std::max(0, size - length), size);
249
})
250
251
DEF(nedf_replace,
252
    "string replace(string s, string substr, string repl, long startPos?)",
253
    "strings",
254
    "Replaces all occurrences of substr in s with the string repl. If startPos is given, search begins from position startPos in s.",
255
{
256
    std::string str = argv[0].s;
257
    std::string& search = argv[1].s;
258
    std::string& replacement = argv[2].s;
259
    size_t index = 0;
260
    if (argc==4) {
261
        if (argv[3].dbl < 0)
262
            throw cRuntimeError("replace(): start index is negative");
263
        index = (size_t)argv[3].dbl;
264
        if (index > str.size())
265
            throw cRuntimeError("replace(): start index out of bounds");
266
    }
267
268
    size_t searchSize = search.size();
269
    size_t replacementSize = replacement.size();
270
    while ((index = str.find(search, index)) != std::string::npos) {
271
        str.replace(index, searchSize, replacement);
272
        index += replacementSize - searchSize + 1;
273
    }
274
    return str;
275
})
276
277
DEF(nedf_replaceFirst,
278
    "string replaceFirst(string s, string substr, string repl, long startPos?)",
279
    "strings",
280
    "Replaces the first occurrence of substr in s with the string repl. If startPos is given, search begins from position startPos in s.",
281
{
282
    std::string str = argv[0].s;
283
    std::string& search = argv[1].s;
284
    std::string& replacement = argv[2].s;
285
    size_t index = 0;
286
    if (argc==4) {
287
        if (argv[3].dbl < 0)
288
            throw cRuntimeError("replaceFirst(): start index is negative");
289
        index = (size_t)argv[3].dbl;
290
        if (index > str.size())
291
            throw cRuntimeError("replaceFirst(): start index out of bounds");
292
    }
293
294
    size_t searchSize = search.size();
295
    if ((index = str.find(search, index)) != std::string::npos)
296
        str.replace(index, searchSize, replacement);
297
    return str;
298
})
299
300
DEF(nedf_trim,
301
    "string trim(string s)",
302
    "strings",
303
    "Discards whitespace from the start and end of s, and returns the result.",
304
{
305
    return opp_trim(argv[0].s.c_str());
306
})
307
308
DEF(nedf_indexOf,
309
    "long indexOf(string s, string substr)",
310
    "strings",
311
    "Returns the position of the first occurrence of substring substr in s, or -1 if s does not contain substr.",
312
{
313
    return (long)argv[0].s.find(argv[1].s);
314
})
315
316
DEF(nedf_choose,
317
    "string choose(long index, string list)",
318
    "strings",
319
    "Interprets list as a space-separated list, and returns the item at the given index. Negative and out-of-bounds indices cause an error.",
320
{
321
    int index = (int)argv[0].dbl;
322
    if (index < 0)
323
        throw cRuntimeError("choose(): negative index");
324
    cStringTokenizer tokenizer(argv[1].s.c_str());
325
    for (int i=0; i<index && tokenizer.hasMoreTokens(); i++)
326
        tokenizer.nextToken();
327
    if (!tokenizer.hasMoreTokens())
328
        throw cRuntimeError("choose(): index out of bounds: %d", index);
329
    return tokenizer.nextToken();
330
})
331
332
DEF(nedf_toUpper,
333
    "string toUpper(string s)",
334
    "strings",
335
    "Converts s to all uppercase, and returns the result.",
336
{
337
    std::string tmp = argv[0].s;
338
    int length = tmp.length();
339
    for (int i=0; i<length; i++)
340
        tmp[i] = opp_toupper(tmp[i]);
341
    return tmp;
342
})
343
344
DEF(nedf_toLower,
345
    "string toLower(string s)",
346
    "strings",
347
    "Converts s to all lowercase, and returns the result.",
348
{
349
    std::string tmp = argv[0].s;
350
    int length = tmp.length();
351
    for (int i=0; i<length; i++)
352
        tmp[i] = opp_tolower(tmp[i]);
353
    return tmp;
354
})
355
356
DEF(nedf_expand,
357
    "string expand(string s)",
358
    "strings",
359
    "Expands ${} variables (${configname}, ${runnumber}, etc.) in the given string, and returns the result.",
360
{
361
    std::string tmp = argv[0].s;
362
    tmp = ev.getConfig()->substituteVariables(tmp.c_str());
363
    return tmp;
364
})
365
366
DEF(nedf_int,
367
    "long int(any x)",
368
    "conversion",
369
    "Converts x to long, and returns the result. A boolean argument becomes 0 or 1; a double is converted using floor(); a string is interpreted as number; an XML argument causes an error.",
370
{
371
    switch (argv[0].type) {
372
        case Value::BOOL:
373
            return argv[0].bl ? 1L : 0L;
374
        case Value::DBL:
375
            return (long)floor(argv[0].dbl);
376
        case Value::STR:
377
            return (long)floor(opp_atof(argv[0].s.c_str()));  //XXX catch & wrap exception?
378
        case Value::XML:
379
            throw cRuntimeError("int(): cannot convert xml to int");
380
        default:
381
            throw cRuntimeError("internal error: bad Value type");
382
    }
383
})
384
385
DEF(nedf_double,
386
    "double double(any x)",
387
    "conversion",
388
    "Converts x to double, and returns the result. A boolean argument becomes 0 or 1; a string is interpreted as number; an XML argument causes an error.",
389
{
390
    switch (argv[0].type) {
391
        case Value::BOOL:
392
            return argv[0].bl ? 1.0 : 0.0;
393
        case Value::DBL:
394
            return argv[0].dbl;
395
        case Value::STR:
396
            return opp_atof(argv[0].s.c_str());  //XXX catch & wrap exception?
397
        case Value::XML:
398
            throw cRuntimeError("double(): cannot convert xml to double");
399
        default:
400
            throw cRuntimeError("internal error: bad Value type");
401
    }
402
})
403
404
DEF(nedf_string,
405
    "string string(any x)",
406
    "conversion",
407
    "Converts x to string, and returns the result.",
408
{
409
    return argv[0].str();
410
})
411
412
413
//
414
// Reflection
415
//
416
417
DEF(nedf_fullPath,
418
    "string fullPath()",
419
    "ned",
420
    "Returns the full path of the module or channel in context.",
421
{
422
    return context->getFullPath();
423
})
424
425
DEF(nedf_fullName,
426
    "string fullName()",
427
    "ned",
428
    "Returns the full name of the module or channel in context.",
429
{
430
    return context->getFullName();
431
})
432
433
DEF(nedf_parentIndex,
434
    "long parentIndex()",
435
    "ned",
436
    "Returns the index of the parent module, which has to be part of module vector.",
437
{
438
    cModule *mod = context->getParentModule();
439
    if (!mod)
440
        throw cRuntimeError("parentIndex(): `%s' has no parent module", context->getFullPath().c_str());
441
    if (!mod->isVector())
442
        throw cRuntimeError("parentIndex(): module `%s' is not a vector", mod->getFullPath().c_str());
443
    return (long)mod->getIndex();
444
})
445
446
DEF(nedf_ancestorIndex,
447
    "long ancestorIndex(long numLevels)",
448
    "ned",
449
    "Returns the index of the ancestor module numLevels levels above the module or channel in context.",
450
{
451
    int levels = (int)argv[0].dbl;
452
    if (levels<0)
453
        throw cRuntimeError("ancestorIndex(): negative number of levels");
454
    if (levels==0 && !context->isModule())
455
        throw cRuntimeError("ancestorIndex(): numlevels==0 and this is not a module");
456
    cModule *mod = dynamic_cast<cModule *>(context);
457
    for (int i=0; mod && i<levels; i++)
458
        mod = mod->getParentModule();
459
    if (!mod)
460
        throw cRuntimeError("ancestorIndex(): argument is larger than current nesting level");
461
    if (!mod->isVector())
462
        throw cRuntimeError("ancestorIndex(): module `%s' is not a vector", mod->getFullPath().c_str());
463
    return (long)mod->getIndex();
464
})
465
466
467
//
468
// Random variate generation.
469
//
470
471
// continuous
472
DEF(nedf_uniform,
473
    "quantity uniform(quantity a, quantity b, long rng?)",
474
    "random/continuous",
475
    "Returns a random number from the Uniform distribution",
476
{
477
    int rng = argc==3 ? (int)argv[2].dbl : 0;
478
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
479
    argv[0].dbl = uniform(argv[0].dbl, argv1converted, rng);
480
    return argv[0];
481
})
482
483
DEF(nedf_exponential,
484
    "quantity exponential(quantity mean, long rng?)",
485
    "random/continuous",
486
    "Returns a random number from the Exponential distribution",
487
{
488
    int rng = argc==2 ? (int)argv[1].dbl : 0;
489
    argv[0].dbl = exponential(argv[0].dbl, rng);
490
    return argv[0];
491
})
492
493
DEF(nedf_normal,
494
    "quantity normal(quantity mean, quantity stddev, long rng?)",
495
    "random/continuous",
496
    "Returns a random number from the Normal distribution",
497
{
498
    int rng = argc==3 ? (int)argv[2].dbl : 0;
499
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
500
    argv[0].dbl = normal(argv[0].dbl, argv1converted, rng);
501
    return argv[0];
502
})
503
504
DEF(nedf_truncnormal,
505
    "quantity truncnormal(quantity mean, quantity stddev, long rng?)",
506
    "random/continuous",
507
    "Returns a random number from the truncated Normal distribution",
508
{
509
    int rng = argc==3 ? (int)argv[2].dbl : 0;
510
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
511
    argv[0].dbl = truncnormal(argv[0].dbl, argv1converted, rng);
512
    return argv[0];
513
})
514
515
DEF(nedf_gamma_d,
516
    "quantity gamma_d(double alpha, quantity theta, long rng?)",
517
    "random/continuous",
518
    "Returns a random number from the Gamma distribution",
519
{
520
    int rng = argc==3 ? (int)argv[2].dbl : 0;
521
    argv[1].dbl = gamma_d(argv[0].dbl, argv[1].dbl, rng);
522
    return argv[1];
523
})
524
525
DEF(nedf_beta,
526
    "double beta(double alpha1, double alpha2, long rng?)",
527
    "random/continuous",
528
    "Returns a random number from the Beta distribution",
529
{
530
    int rng = argc==3 ? (int)argv[2].dbl : 0;
531
    argv[0].dbl = beta(argv[0].dbl, argv[1].dbl, rng);
532
    return argv[0];
533
})
534
535
DEF(nedf_erlang_k,
536
    "quantity erlang_k(long k, quantity mean, long rng?)",
537
    "random/continuous",
538
    "Returns a random number from the Erlang distribution",
539
{
540
    if (argv[0].dbl < 0.0)
541
       throw cRuntimeError("erlang_k(): k parameter (number of phases) must be positive "
542
                           "(k=%g", argv[0].dbl);
543
    int rng = argc==3 ? (int)argv[2].dbl : 0;
544
    argv[1].dbl = erlang_k((unsigned int)argv[0].dbl, argv[1].dbl, rng);
545
    return argv[1];
546
})
547
548
DEF(nedf_chi_square,
549
    "double chi_square(long k, long rng?)",
550
    "random/continuous",
551
    "Returns a random number from the Chi-square distribution",
552
{
553
    if (argv[0].dbl < 0.0)
554
       throw cRuntimeError("chi_square(): k parameter (degrees of freedom) must be positive "
555
                           "(k=%g", argv[0].dbl);
556
    int rng = argc==2 ? (int)argv[1].dbl : 0;
557
    argv[0].dbl = chi_square((unsigned int)argv[0].dbl, rng);
558
    return argv[0];
559
})
560
561
DEF(nedf_student_t,
562
    "double student_t(long i, long rng?)",
563
    "random/continuous",
564
    "Returns a random number from the Student-t distribution",
565
{
566
    if (argv[0].dbl < 0.0)
567
       throw cRuntimeError("student_t(): i parameter (degrees of freedom) must be positive "
568
                           "(i=%g", argv[0].dbl);
569
    int rng = argc==2 ? (int)argv[1].dbl : 0;
570
    argv[0].dbl = student_t((unsigned int)argv[0].dbl, rng);
571
    return argv[0];
572
})
573
574
DEF(nedf_cauchy,
575
    "quantity cauchy(quantity a, quantity b, long rng?)",
576
    "random/continuous",
577
    "Returns a random number from the Cauchy distribution",
578
{
579
    int rng = argc==3 ? (int)argv[2].dbl : 0;
580
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
581
    argv[0].dbl = cauchy(argv[0].dbl, argv1converted, rng);
582
    return argv[0];
583
})
584
585
DEF(nedf_triang,
586
    "quantity triang(quantity a, quantity b, quantity c, long rng?)",
587
    "random/continuous",
588
    "Returns a random number from the Triangular distribution",
589
{
590
    int rng = argc==4 ? (int)argv[3].dbl : 0;
591
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
592
    double argv2converted = UnitConversion::convertUnit(argv[2].dbl, argv[2].dblunit, argv[0].dblunit);
593
    argv[0].dbl = triang(argv[0].dbl, argv1converted, argv2converted, rng);
594
    return argv[0];
595
})
596
597
DEF(nedf_lognormal,
598
    "double lognormal(double m, double w, long rng?)",
599
    "random/continuous",
600
    "Returns a random number from the Lognormal distribution",
601
{
602
    int rng = argc==3 ? (int)argv[2].dbl : 0;
603
    argv[0].dbl = lognormal(argv[0].dbl, argv[1].dbl, rng);
604
    return argv[0];
605
})
606
607
DEF(nedf_weibull,
608
    "quantity weibull(quantity a, quantity b, long rng?)",
609
    "random/continuous",
610
    "Returns a random number from the Weibull distribution",
611
{
612
    int rng = argc==3 ? (int)argv[2].dbl : 0;
613
    double argv1converted = UnitConversion::convertUnit(argv[1].dbl, argv[1].dblunit, argv[0].dblunit);
614
    argv[0].dbl = weibull(argv[0].dbl, argv1converted, rng);
615
    return argv[0];
616
})
617
618
DEF(nedf_pareto_shifted,
619
    "quantity pareto_shifted(double a, quantity b, quantity c, long rng?)",
620
    "random/continuous",
621
    "Returns a random number from the Pareto-shifted distribution",
622
{
623
    int rng = argc==4 ? (int)argv[3].dbl : 0;
624
    double argv2converted = UnitConversion::convertUnit(argv[2].dbl, argv[2].dblunit, argv[1].dblunit);
625
    argv[1].dbl = pareto_shifted(argv[0].dbl, argv[1].dbl, argv2converted, rng);
626
    return argv[1];
627
})
628
629
// discrete
630
631
DEF(nedf_intuniform,
632
    "long intuniform(long a, long b, long rng?)",
633
    "random/discrete",
634
    "Returns a random number from the Intuniform distribution",
635
{
636
    int rng = argc==3 ? (int)argv[2].dbl : 0;
637
    argv[0].dbl = intuniform((int)argv[0].dbl, (int)argv[1].dbl, rng);
638
    return argv[0];
639
})
640
641
DEF(nedf_bernoulli,
642
    "long bernoulli(double p, long rng?)",
643
    "random/discrete",
644
    "Returns a random number from the Bernoulli distribution",
645
{
646
    int rng = argc==2 ? (int)argv[1].dbl : 0;
647
    argv[0].dbl = bernoulli(argv[0].dbl, rng);
648
    return argv[0];
649
})
650
651
DEF(nedf_binomial,
652
    "long binomial(long n, double p, long rng?)",
653
    "random/discrete",
654
    "Returns a random number from the Binomial distribution",
655
{
656
    int rng = argc==3 ? (int)argv[2].dbl : 0;
657
    argv[0].dbl = binomial((int)argv[0].dbl, argv[1].dbl, rng);
658
    return argv[0];
659
})
660
661
DEF(nedf_geometric,
662
    "long geometric(double p, long rng?)",
663
    "random/discrete",
664
    "Returns a random number from the Geometric distribution",
665
{
666
    int rng = argc==2 ? (int)argv[1].dbl : 0;
667
    argv[0].dbl = geometric(argv[0].dbl, rng);
668
    return argv[0];
669
})
670
671
DEF(nedf_negbinomial,
672
    "long negbinomial(long n, double p, long rng?)",
673
    "random/discrete",
674
    "Returns a random number from the Negbinomial distribution",
675
{
676
    int rng = argc==3 ? (int)argv[2].dbl : 0;
677
    argv[0].dbl = negbinomial((int)argv[0].dbl, argv[1].dbl, rng);
678
    return argv[0];
679
})
680
681
DEF(nedf_poisson,
682
    "long poisson(double lambda, long rng?)",
683
    "random/discrete",
684
    "Returns a random number from the Poisson distribution",
685
{
686
    int rng = argc==2 ? (int)argv[1].dbl : 0;
687
    argv[0].dbl = poisson(argv[0].dbl, rng);
688
    return argv[0];
689
})
690
691
692
//
693
// misc utility functions
694
//
695
696
DEF(nedf_simTime,
697
    "quantity simTime()",
698
    "misc",
699
    "Returns the current simulation time.",
700
{
701
    return Value(SIMTIME_DBL(simTime()), "s");
702
})