Module 7 · Probability Distributions and Simulation Basics Lesson 61 of 120
PMF, PDF, CDF, Survival, and Quantile Functions
Turning a loss model into probabilities and thresholds.
Transcript
20 sentences · select one to jump thereCheck your understanding
Can a PDF have height two without violating probability rules?
Code lab
Run it yourself
The lesson source in 7 languages. Edit it, run TypeScript and Python right here, and compare with the expected output.
/**
* Fintech Math Bootcamp · Lesson 061 of 120
* PMF, PDF, CDF, Survival, and Quantile Functions
* Module 07: Probability Distributions and Simulation Basics
*
* Scenario: Turning a loss model into probabilities and thresholds
* Rule: F(x)=P(X≤x); S(x)=1−F(x); Q(p)=inf{x:F(x)≥p}
*
* Try it: Can a PDF have height two without violating probability rules?
*
* Lesson article: https://thefintechbuilder.com/financial-mathematics-statistics-and-data-foundations/probability-distributions-and-simulation-basics/pmf-pdf-cdf-survival-and-quantile-functions/
* Free course: https://courses.thefintechbuilder.com
* Synthetic teaching example, not financial advice or a production library.
*/
export function lesson061() {
const values=[0,1,2], p=[.2,.5,.3];
const cdf=(x:number)=>values.reduce((s,v,i)=>s+(v<=x?p[i]:0),0);
const quantile=(u:number)=>values.find(v=>cdf(v)>=u)!;
const result={pmfAt1:p[1],cdfAt1:cdf(1),survivalAt1:1-cdf(1),q80:quantile(.8)};
return result;
}
export const checkedResult = {"pmfAt1":0.5,"cdfAt1":0.7,"survivalAt1":0.30000000000000004,"q80":2};
// Run this file directly: npx tsx lessons/07-probability-distributions-and-simulation-basics/061-pmf-pdf-cdf-survival-and-quantile-functions.ts
if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/\\/g, "/").split("/").pop()!)) {
console.log(JSON.stringify(lesson061(), null, 2));
}
Your output
Press Run to execute the code in your browser.
Expected output
{
"pmfAt1": 0.5,
"cdfAt1": 0.7,
"survivalAt1": 0.30000000000000004,
"q80": 2
}"""
Fintech Math Bootcamp · Lesson 061 of 120
PMF, PDF, CDF, Survival, and Quantile Functions
Module 07: Probability Distributions and Simulation Basics
Scenario: Turning a loss model into probabilities and thresholds
Rule: F(x)=P(X≤x); S(x)=1−F(x); Q(p)=inf{x:F(x)≥p}
Try it: Can a PDF have height two without violating probability rules?
Lesson article: https://thefintechbuilder.com/financial-mathematics-statistics-and-data-foundations/probability-distributions-and-simulation-basics/pmf-pdf-cdf-survival-and-quantile-functions/
Free course: https://courses.thefintechbuilder.com
Synthetic teaching example, not financial advice or a production library.
"""
import json
def lesson_061():
values = [0, 1, 2]
p = [0.2, 0.5, 0.3]
def cdf(x):
total = 0
for v, prob in zip(values, p):
total += prob if v <= x else 0
return total
def quantile(u):
return next(v for v in values if cdf(v) >= u)
return {
"pmfAt1": p[1],
"cdfAt1": cdf(1),
"survivalAt1": 1 - cdf(1),
"q80": quantile(0.8),
}
if __name__ == "__main__":
print(json.dumps(lesson_061(), indent=2))
Your output
Press Run to execute the code in your browser.
Expected output
{
"pmfAt1": 0.5,
"cdfAt1": 0.7,
"survivalAt1": 0.30000000000000004,
"q80": 2
}// Fintech Math Bootcamp - Lesson 061 of 120
// PMF, PDF, CDF, Survival, and Quantile Functions
// Module 07: Probability Distributions and Simulation Basics
//
// Scenario: Turning a loss model into probabilities and thresholds
// Rule: F(x)=P(X<=x); S(x)=1-F(x); Q(p)=inf{x:F(x)>=p}
//
// Try it: Can a PDF have height two without violating probability rules?
//
// Lesson article: https://thefintechbuilder.com/financial-mathematics-statistics-and-data-foundations/probability-distributions-and-simulation-basics/pmf-pdf-cdf-survival-and-quantile-functions/
// Free course: https://courses.thefintechbuilder.com
// Synthetic teaching example, not financial advice or a production library.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class Main {
static Map<String, Object> lesson061() {
double[] values = {0, 1, 2};
double[] p = {0.2, 0.5, 0.3};
Map<String, Object> result = new LinkedHashMap<String, Object>();
result.put("pmfAt1", p[1]);
result.put("cdfAt1", cdf(values, p, 1));
result.put("survivalAt1", 1 - cdf(values, p, 1));
result.put("q80", quantile(values, p, 0.8));
return result;
}
// F(x) = P(X <= x)
static double cdf(double[] values, double[] p, double x) {
double total = 0;
for (int i = 0; i < values.length; i++) {
total += values[i] <= x ? p[i] : 0;
}
return total;
}
// Q(u) = smallest value whose CDF reaches u
static double quantile(double[] values, double[] p, double u) {
for (double v : values) {
if (cdf(values, p, v) >= u) return v;
}
throw new IllegalArgumentException("quantile level above total probability");
}
public static void main(String[] args) {
System.out.println(toJson(lesson061(), ""));
}
// Minimal JSON writer: two-space indent, whole numbers without a decimal point, NaN as null.
static String toJson(Object value, String indent) {
if (value == null) return "null";
if (value instanceof Boolean) return value.toString();
if (value instanceof Number) return formatNumber(((Number) value).doubleValue());
if (value instanceof String) return quote((String) value);
if (value instanceof double[]) {
List<Object> boxed = new ArrayList<Object>();
for (double d : (double[]) value) boxed.add(d);
return toJson(boxed, indent);
}
if (value instanceof Object[]) return toJson(Arrays.asList((Object[]) value), indent);
String inner = indent + " ";
StringBuilder out = new StringBuilder();
if (value instanceof Map) {
Map<?, ?> map = (Map<?, ?>) value;
if (map.isEmpty()) return "{}";
out.append("{\n");
int i = 0;
for (Map.Entry<?, ?> entry : map.entrySet()) {
out.append(inner).append(quote(entry.getKey().toString())).append(": ")
.append(toJson(entry.getValue(), inner));
out.append(++i < map.size() ? ",\n" : "\n");
}
return out.append(indent).append("}").toString();
}
List<?> list = (List<?>) value;
if (list.isEmpty()) return "[]";
out.append("[\n");
for (int i = 0; i < list.size(); i++) {
out.append(inner).append(toJson(list.get(i), inner));
out.append(i + 1 < list.size() ? ",\n" : "\n");
}
return out.append(indent).append("]").toString();
}
static String formatNumber(double x) {
if (Double.isNaN(x) || Double.isInfinite(x)) return "null";
if (x == Math.rint(x) && Math.abs(x) < 1e15) return Long.toString((long) x);
return Double.toString(x);
}
static String quote(String s) {
StringBuilder out = new StringBuilder("\"");
for (char c : s.toCharArray()) {
if (c == '"' || c == '\\') out.append('\\').append(c);
else if (c == '\n') out.append("\\n");
else if (c < 0x20) out.append(String.format("\\u%04x", (int) c));
else out.append(c);
}
return out.append('"').toString();
}
}
No browser runner for Java yet
Read the code here, then run it in your own toolchain or a ready-made cloud workspace.
Expected output
{
"pmfAt1": 0.5,
"cdfAt1": 0.7,
"survivalAt1": 0.30000000000000004,
"q80": 2
}// Fintech Math Bootcamp · Lesson 061 of 120
// PMF, PDF, CDF, Survival, and Quantile Functions
// Module 07: Probability Distributions and Simulation Basics
//
// Scenario: Turning a loss model into probabilities and thresholds
// Rule: F(x)=P(X≤x); S(x)=1−F(x); Q(p)=inf{x:F(x)≥p}
//
// Try it: Can a PDF have height two without violating probability rules?
//
// Lesson article: https://thefintechbuilder.com/financial-mathematics-statistics-and-data-foundations/probability-distributions-and-simulation-basics/pmf-pdf-cdf-survival-and-quantile-functions/
// Free course: https://courses.thefintechbuilder.com
// Synthetic teaching example, not financial advice or a production library.
package main
import (
"encoding/json"
"fmt"
)
type Lesson061Result struct {
PmfAt1 float64 `json:"pmfAt1"`
CdfAt1 float64 `json:"cdfAt1"`
SurvivalAt1 float64 `json:"survivalAt1"`
Q80 float64 `json:"q80"`
}
func lesson061() Lesson061Result {
values := []float64{0, 1, 2}
p := []float64{0.2, 0.5, 0.3}
cdf := func(x float64) float64 {
total := 0.0
for i, v := range values {
if v <= x {
total += p[i]
}
}
return total
}
quantile := func(u float64) float64 {
for _, v := range values {
if cdf(v) >= u {
return v
}
}
panic("quantile level above total probability")
}
return Lesson061Result{
PmfAt1: p[1],
CdfAt1: cdf(1),
SurvivalAt1: 1 - cdf(1),
Q80: quantile(0.8),
}
}
func main() {
out, err := json.MarshalIndent(lesson061(), "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
No browser runner for Go yet
Read the code here, then run it in your own toolchain or a ready-made cloud workspace.
Expected output
{
"pmfAt1": 0.5,
"cdfAt1": 0.7,
"survivalAt1": 0.30000000000000004,
"q80": 2
}// Fintech Math Bootcamp · Lesson 061 of 120
// PMF, PDF, CDF, Survival, and Quantile Functions
// Module 07: Probability Distributions and Simulation Basics
//
// Scenario: Turning a loss model into probabilities and thresholds
// Rule: F(x)=P(X≤x); S(x)=1−F(x); Q(p)=inf{x:F(x)≥p}
//
// Try it: Can a PDF have height two without violating probability rules?
//
// Lesson article: https://thefintechbuilder.com/financial-mathematics-statistics-and-data-foundations/probability-distributions-and-simulation-basics/pmf-pdf-cdf-survival-and-quantile-functions/
// Free course: https://courses.thefintechbuilder.com
// Synthetic teaching example, not financial advice or a production library.
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
// A minimal JSON value, enough to print this lesson's result.
struct Json {
enum class Kind { Null, Bool, Number, String, Array, Object };
Kind kind = Kind::Null;
bool flag = false;
double number = 0.0;
std::string text;
std::vector<std::string> keys; // object keys, parallel to items
std::vector<Json> items; // array elements or object values
Json() = default;
Json(bool value) : kind(Kind::Bool), flag(value) {}
Json(int value) : kind(Kind::Number), number(value) {}
Json(double value) : kind(Kind::Number), number(value) {}
Json(const char* value) : kind(Kind::String), text(value) {}
Json(const std::string& value) : kind(Kind::String), text(value) {}
Json(const std::vector<double>& values) : kind(Kind::Array) {
for (double v : values) items.push_back(Json(v));
}
};
Json jsonArray(const std::vector<Json>& values) {
Json array;
array.kind = Json::Kind::Array;
array.items = values;
return array;
}
Json jsonObject(const std::vector<std::pair<std::string, Json>>& fields) {
Json object;
object.kind = Json::Kind::Object;
for (const auto& field : fields) {
object.keys.push_back(field.first);
object.items.push_back(field.second);
}
return object;
}
// Shortest decimal form that reads back as the same double.
std::string formatNumber(double x) {
if (!std::isfinite(x)) return "null";
char buffer[32];
if (x == std::floor(x) && std::fabs(x) < 1e15) {
std::snprintf(buffer, sizeof buffer, "%.0f", x);
return buffer;
}
for (int precision = 1; precision <= 17; ++precision) {
std::snprintf(buffer, sizeof buffer, "%.*g", precision, x);
if (std::strtod(buffer, nullptr) == x) break;
}
return buffer;
}
std::string quote(const std::string& s) {
std::string out = "\"";
for (char c : s) {
if (c == '"' || c == '\\') { out += '\\'; out += c; }
else if (c == '\n') out += "\\n";
else out += c;
}
return out + "\"";
}
std::string toJson(const Json& value, const std::string& indent = "") {
switch (value.kind) {
case Json::Kind::Null: return "null";
case Json::Kind::Bool: return value.flag ? "true" : "false";
case Json::Kind::Number: return formatNumber(value.number);
case Json::Kind::String: return quote(value.text);
default: break;
}
const bool isObject = value.kind == Json::Kind::Object;
if (value.items.empty()) return isObject ? "{}" : "[]";
const std::string inner = indent + " ";
std::string out = isObject ? "{\n" : "[\n";
for (std::size_t i = 0; i < value.items.size(); ++i) {
out += inner;
if (isObject) out += quote(value.keys[i]) + ": ";
out += toJson(value.items[i], inner);
out += i + 1 < value.items.size() ? ",\n" : "\n";
}
return out + indent + (isObject ? "}" : "]");
}
Json lesson061() {
const std::vector<double> values = {0, 1, 2};
const std::vector<double> p = {0.2, 0.5, 0.3};
// F(x) = P(X <= x)
auto cdf = [&](double x) {
double total = 0.0;
for (std::size_t i = 0; i < values.size(); ++i) total += values[i] <= x ? p[i] : 0.0;
return total;
};
// Q(u) = smallest value whose CDF reaches u
auto quantile = [&](double u) {
for (double v : values) {
if (cdf(v) >= u) return v;
}
throw std::domain_error("quantile level above total probability");
};
return jsonObject({
{"pmfAt1", p[1]},
{"cdfAt1", cdf(1)},
{"survivalAt1", 1 - cdf(1)},
{"q80", quantile(0.8)},
});
}
int main() {
try {
std::cout << toJson(lesson061()) << '\n';
} catch (const std::exception& error) {
std::cerr << "Error: " << error.what() << '\n';
return 1;
}
return 0;
}
No browser runner for C++ yet
Read the code here, then run it in your own toolchain or a ready-made cloud workspace.
Expected output
{
"pmfAt1": 0.5,
"cdfAt1": 0.7,
"survivalAt1": 0.30000000000000004,
"q80": 2
}// Fintech Math Bootcamp · Lesson 061 of 120
// PMF, PDF, CDF, Survival, and Quantile Functions
// Module 07: Probability Distributions and Simulation Basics
//
// Scenario: Turning a loss model into probabilities and thresholds
// Rule: F(x)=P(X≤x); S(x)=1−F(x); Q(p)=inf{x:F(x)≥p}
//
// Try it: Can a PDF have height two without violating probability rules?
//
// Lesson article: https://thefintechbuilder.com/financial-mathematics-statistics-and-data-foundations/probability-distributions-and-simulation-basics/pmf-pdf-cdf-survival-and-quantile-functions/
// Free course: https://courses.thefintechbuilder.com
// Synthetic teaching example, not financial advice or a production library.
/// A minimal JSON value, enough to print this lesson's result.
#[allow(dead_code)]
enum Json {
Null,
Bool(bool),
Num(f64),
Str(String),
Arr(Vec<Json>),
Obj(Vec<(String, Json)>),
}
#[allow(dead_code)]
impl Json {
fn obj(fields: Vec<(&str, Json)>) -> Json {
Json::Obj(fields.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
}
fn nums(values: &[f64]) -> Json {
Json::Arr(values.iter().map(|&v| Json::Num(v)).collect())
}
/// Pretty-prints with two-space indentation.
fn pretty(&self, indent: &str) -> String {
let inner = format!("{} ", indent);
match self {
Json::Null => "null".to_string(),
Json::Bool(b) => b.to_string(),
Json::Num(x) => format_number(*x),
Json::Str(s) => quote(s),
Json::Arr(items) if items.is_empty() => "[]".to_string(),
Json::Obj(fields) if fields.is_empty() => "{}".to_string(),
Json::Arr(items) => {
let body: Vec<String> = items
.iter()
.map(|v| format!("{}{}", inner, v.pretty(&inner)))
.collect();
format!("[\n{}\n{}]", body.join(",\n"), indent)
}
Json::Obj(fields) => {
let body: Vec<String> = fields
.iter()
.map(|(k, v)| format!("{}{}: {}", inner, quote(k), v.pretty(&inner)))
.collect();
format!("{{\n{}\n{}}}", body.join(",\n"), indent)
}
}
}
}
fn format_number(x: f64) -> String {
if !x.is_finite() {
"null".to_string()
} else if x == x.trunc() && x.abs() < 1e15 {
format!("{}", x as i64)
} else {
format!("{}", x)
}
}
fn quote(s: &str) -> String {
let mut out = String::from("\"");
for c in s.chars() {
match c {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
c => out.push(c),
}
}
out.push('"');
out
}
fn lesson_061() -> Json {
let values = [0.0_f64, 1.0, 2.0];
let p = [0.2_f64, 0.5, 0.3];
// F(x) = P(X <= x)
let cdf = |x: f64| -> f64 {
values
.iter()
.zip(p.iter())
.fold(0.0_f64, |s, (&v, &prob)| s + if v <= x { prob } else { 0.0 })
};
// Q(u) = smallest value whose CDF reaches u
let quantile = |u: f64| -> f64 {
*values
.iter()
.find(|&&v| cdf(v) >= u)
.expect("quantile level above total probability")
};
Json::obj(vec![
("pmfAt1", Json::Num(p[1])),
("cdfAt1", Json::Num(cdf(1.0))),
("survivalAt1", Json::Num(1.0 - cdf(1.0))),
("q80", Json::Num(quantile(0.8))),
])
}
fn main() {
println!("{}", lesson_061().pretty(""));
}
No browser runner for Rust yet
Read the code here, then run it in your own toolchain or a ready-made cloud workspace.
Expected output
{
"pmfAt1": 0.5,
"cdfAt1": 0.7,
"survivalAt1": 0.30000000000000004,
"q80": 2
}// Fintech Math Bootcamp · Lesson 061 of 120
// PMF, PDF, CDF, Survival, and Quantile Functions
// Module 07: Probability Distributions and Simulation Basics
//
// Scenario: Turning a loss model into probabilities and thresholds
// Rule: F(x)=P(X≤x); S(x)=1−F(x); Q(p)=inf{x:F(x)≥p}
//
// Try it: Can a PDF have height two without violating probability rules?
//
// Lesson article: https://thefintechbuilder.com/financial-mathematics-statistics-and-data-foundations/probability-distributions-and-simulation-basics/pmf-pdf-cdf-survival-and-quantile-functions/
// Free course: https://courses.thefintechbuilder.com
// Synthetic teaching example, not financial advice or a production library.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(JsonSerializer.Serialize(Lesson061(), options));
static object Lesson061()
{
double[] values = { 0, 1, 2 };
double[] p = { 0.2, 0.5, 0.3 };
// F(x) = P(X <= x)
double Cdf(double x) => values.Select((v, i) => v <= x ? p[i] : 0.0).Aggregate(0.0, (s, term) => s + term);
// Q(u) = smallest value whose CDF reaches u
double Quantile(double u) => values.First(v => Cdf(v) >= u);
return new
{
pmfAt1 = p[1],
cdfAt1 = Cdf(1),
survivalAt1 = 1 - Cdf(1),
q80 = Quantile(0.8),
};
}
No browser runner for C# yet
Read the code here, then run it in your own toolchain or a ready-made cloud workspace.
Expected output
{
"pmfAt1": 0.5,
"cdfAt1": 0.7,
"survivalAt1": 0.30000000000000004,
"q80": 2
}Prefer your own machine? Every file is in the course repository · open it in Codespaces.
Lesson notes
The rule
F(x)=P(X≤x); S(x)=1−F(x); Q(p)=inf{x:F(x)≥p}