diff --git a/src/App.svelte b/src/App.svelte index b8159c0b8956036ed366c30e3b35d247c1fb175c..4a847810f0d907ab558ea970422fb1838eda40a3 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -7,6 +7,8 @@ import type { WorkPackage } from "./estimator"; const NUMBER_OF_WORKPACKAGES = 10; let workPackages: WorkPackage[] = [] + export let r: number = 4; + export let u: number = 6; for (let i = 0; i <= NUMBER_OF_WORKPACKAGES; i++) { workPackages.push({a: null, b:null, c: null}); } @@ -15,6 +17,11 @@ import type { WorkPackage } from "./estimator"; </script> <main> + r: + <input type="number" bind:value={r}> + u: + <input type="number" bind:value={u}> + <br> <table class="tg"> <thead> <th class="tg-0lax">a</th> @@ -27,7 +34,7 @@ import type { WorkPackage } from "./estimator"; </thead> <tbody> {#each workPackages as workPackage, i (i)} - <RowWorkItem bind:a={workPackage.a} bind:b={workPackage.b} bind:c={workPackage.c}></RowWorkItem> + <RowWorkItem bind:a={workPackage.a} bind:b={workPackage.b} bind:c={workPackage.c} u={u} r={r}></RowWorkItem> {/each} <SumRow {workPackages}></SumRow> </tbody> diff --git a/src/RowWorkItem.svelte b/src/RowWorkItem.svelte index 8c433b3a660e64b830610e0f6c9f26c6ea7f28dd..c561e27078f67e5d4e9e620863ae931687b75716 100644 --- a/src/RowWorkItem.svelte +++ b/src/RowWorkItem.svelte @@ -5,9 +5,11 @@ export let a: number export let b: number export let c: number; - $: E = ( typeof a !== "number" || typeof b !== "number") ? null : calculateE({a,b,c}) - $: S = ( typeof a !== "number" || typeof b !== "number") ? null : calculateS({a,b,c}) - $: V = ( typeof a !== "number" || typeof b !== "number") ? null : calculateV({a,b,c}) + export let r: number = NaN; + export let u: number = NaN; + $: E = ( typeof a !== "number" || typeof b !== "number") ? null : calculateE({a,b,c}, r) + $: S = ( typeof a !== "number" || typeof b !== "number") ? null : calculateS({a,b,c}, u) + $: V = ( typeof a !== "number" || typeof b !== "number") ? null : calculateV({a,b,c}, u) $: SEPercent = (typeof S !== 'number' || typeof E !== 'number') ? null : (S/E)*100 function hideNull(input: any|null): string { diff --git a/src/SumRow.svelte b/src/SumRow.svelte index 0bc0eca80c703e1ec9f34be25dbf6f5a3801970f..0f6b015f84ed536ed6188bfc9ad2fbd9e9cb3e47 100644 --- a/src/SumRow.svelte +++ b/src/SumRow.svelte @@ -4,6 +4,8 @@ import { roundOne, sumIgnoreNonNumbers } from "./utils"; export let workPackages: WorkPackage[] + export let r: number = NaN; + export let u: number = NaN; </script> <tr> <td class="tg-0lax"> @@ -16,10 +18,10 @@ ∑ {sumIgnoreNonNumbers(workPackages.map(workPackage => workPackage.b))} </td> <td class="tg-0lax"> - ∑ {roundOne(calculateESum(workPackages))} + ∑ {roundOne(calculateESum(workPackages, r))} </td> <td class="tg-0lax"> - {roundOne(calculateSSum(workPackages))} + {roundOne(calculateSSum(workPackages, u))} </td> <td class="tg-0lax"> </td> diff --git a/src/estimator.ts b/src/estimator.ts index b7491542261319fc6cc8f986d9048f175a6336ce..e11e4bf5ac9b140a9633368131953cdf29a099e8 100644 --- a/src/estimator.ts +++ b/src/estimator.ts @@ -12,7 +12,7 @@ export interface WorkPackage { /** * Calculate the expected effort for a given workpackage */ -export function calculateE(workPackage: WorkPackage): number { +export function calculateE(workPackage: WorkPackage, r: number): number { const { a, b, c } = workPackage; if ( typeof a !== "number" || @@ -24,39 +24,45 @@ export function calculateE(workPackage: WorkPackage): number { } return typeof c !== "number" || c === null ? (a + b) / 2 - : (a + 4 * c + b) / 6; + : (a + r * c + b) / 6; } -export function calculateV(workPackage: WorkPackage): number { +/** + * Calculate the variance of the expected effort for a given workpackage + */ +export function calculateV(workPackage: WorkPackage, u: number): number { const { a, b } = workPackage; if (typeof a !== "number" || typeof b !== "number") { throw new TypeError("@calculateV(): a and b must be numbers"); } - return ((b - a) * (b - a)) / 36; + return ((b - a) * (b - a)) / u ** 2; } -export function calculateS(workPackage: WorkPackage): number { +/** + * Calculate the standard deviation of the expected effort for a given workpackage + */ +export function calculateS(workPackage: WorkPackage, u: number): number { const { a, b } = workPackage; if (typeof a !== "number" || typeof b !== "number") { throw new TypeError("@calculateS(): a and b must be numbers"); } - return (b - a) / 6; + return (b - a) / u; } -export function calculateSSum(workPackages: WorkPackage[]): number { +export function calculateSSum(workPackages: WorkPackage[], u: number): number { return Math.sqrt( sumIgnoreNonNumbers( workPackages .filter(({ a, b }) => typeof a === "number" && typeof b === "number") - .map((workPackage) => calculateS(workPackage) ** 2) + .map((workPackage) => calculateS(workPackage, u) ** 2) ) ); } -export function calculateESum(workPackages: WorkPackage[]): number { +export function calculateESum(workPackages: WorkPackage[], r: number): number { return sumIgnoreNonNumbers( workPackages .filter(({ a, b }) => typeof a === "number" && typeof b === "number") - .map((workPackage) => calculateE(workPackage)) + .map((workPackage) => calculateE(workPackage, r)) ); } diff --git a/src/test/estimator.spec.ts b/src/test/estimator.spec.ts index 86caa02e4f9ca7715d4cf16529c28f9b8cde8ff5..880973909f82dc56f543560ec86511984c410238 100644 --- a/src/test/estimator.spec.ts +++ b/src/test/estimator.spec.ts @@ -5,58 +5,56 @@ import { assert } from "chai"; const roundOne = (n) => Math.round(n * Math.pow(10, 1)) / Math.pow(10, 1); describe("Estimator Calculation", function () { + const r = 4; + const u = 6; describe("#calculateE()", function () { it("should return 100, if a and b are 100 and c undefined", function () { - assert.equal(calculateE({ a: 100, b: 100 }), 100); + assert.equal(calculateE({ a: 100, b: 100 }, r), 100); }); it("should return 100, if a and b are 100 and c null", function () { - assert.equal(calculateE({ a: 100, b: 100, c: null }), 100); + assert.equal(calculateE({ a: 100, b: 100, c: null }, r), 100); }); it("should return 50, if a = 0, b = 100 and c null", function () { - assert.equal(calculateE({ a: 0, b: 100, c: null }), 50); + assert.equal(calculateE({ a: 0, b: 100, c: null }, r), 50); }); it("should return 50, if a = 0, b = 100 and c = 50", function () { - assert.equal(calculateE({ a: 0, b: 100, c: 50 }), 50); + assert.equal(calculateE({ a: 0, b: 100, c: 50 }, r), 50); }); describe("Vorlesungsbeispiele:", function () { it("should return 36.7, if {a,c,b} = {20,30,80}", function () { - assert.equal(roundOne(calculateE({ a: 20, c: 30, b: 80 })), 36.7); + assert.equal(roundOne(calculateE({ a: 20, c: 30, b: 80 }, r)), 36.7); }); it("should return 20, if {a,c,b} = {10,20,30}", function () { - assert.equal(roundOne(calculateE({ a: 10, c: 20, b: 30 })), 20); + assert.equal(roundOne(calculateE({ a: 10, c: 20, b: 30 }, r)), 20); }); it("should return 20.8, if {a,c,b} = {15,20,30}", function () { - assert.equal(roundOne(calculateE({ a: 15, c: 20, b: 30 })), 20.8); + assert.equal(roundOne(calculateE({ a: 15, c: 20, b: 30 }, r)), 20.8); }); it("should return 9.5, if {a,c,b} = {5,8,20}", function () { - assert.equal(roundOne(calculateE({ a: 5, c: 8, b: 20 })), 9.5); + assert.equal(roundOne(calculateE({ a: 5, c: 8, b: 20 }, r)), 9.5); }); }); }); describe("#calculateV()", function () { describe("Vorlesungsbeispiele:", function () { - it("should return 36.7, if {a,c,b} = {20,30,80}", function () { - assert.equal(roundOne(calculateE({ a: 20, c: 30, b: 80 })), 36.7); - }); - it("should return 11.1, if {a,c,b} = {10,20,30}", function () { - assert.equal(roundOne(calculateV({ a: 10, c: 20, b: 30 })), 11.1); + assert.equal(roundOne(calculateV({ a: 10, c: 20, b: 30 }, u)), 11.1); }); it("should return 6.3, if {a,c,b} = {15,20,30}", function () { - assert.equal(roundOne(calculateV({ a: 15, c: 20, b: 30 })), 6.3); + assert.equal(roundOne(calculateV({ a: 15, c: 20, b: 30 }, u)), 6.3); }); it("should return 6.3, if {a,c,b} = {5,8,20}", function () { - assert.equal(roundOne(calculateV({ a: 5, c: 8, b: 20 })), 6.3); + assert.equal(roundOne(calculateV({ a: 5, c: 8, b: 20 }, u)), 6.3); }); }); }); @@ -64,19 +62,19 @@ describe("Estimator Calculation", function () { describe("#calculateS()", function () { describe("Vorlesungsbeispiele:", function () { it("should return 10, if {a,c,b} = {20,30,80}", function () { - assert.equal(roundOne(calculateS({ a: 20, c: 30, b: 80 })), 10); + assert.equal(roundOne(calculateS({ a: 20, c: 30, b: 80 }, u)), 10); }); it("should return 3.3, if {a,c,b} = {10,20,30}", function () { - assert.equal(roundOne(calculateS({ a: 10, c: 20, b: 30 })), 3.3); + assert.equal(roundOne(calculateS({ a: 10, c: 20, b: 30 }, u)), 3.3); }); it("should return 2.5, if {a,c,b} = {15,20,30}", function () { - assert.equal(roundOne(calculateS({ a: 15, c: 20, b: 30 })), 2.5); + assert.equal(roundOne(calculateS({ a: 15, c: 20, b: 30 }, u)), 2.5); }); it("should return 2.5, if {a,c,b} = {5,8,20}", function () { - assert.equal(roundOne(calculateS({ a: 5, c: 8, b: 20 })), 2.5); + assert.equal(roundOne(calculateS({ a: 5, c: 8, b: 20 }, u)), 2.5); }); }); });