diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 1afc0fec..c3f0fd99 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -112,6 +112,7 @@
+
diff --git a/src/Numerics/Statistics/ArrayStatistics.cs b/src/Numerics/Statistics/ArrayStatistics.cs
index f9743e61..9383347c 100644
--- a/src/Numerics/Statistics/ArrayStatistics.cs
+++ b/src/Numerics/Statistics/ArrayStatistics.cs
@@ -28,6 +28,8 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using System;
+
namespace MathNet.Numerics.Statistics
{
public static class ArrayStatistics
@@ -42,7 +44,8 @@ namespace MathNet.Numerics.Statistics
/// Sample array, no sorting is assumed.
public static double Minimum(double[] data)
{
- if (data == null || data.Length == 0) return double.NaN;
+ if (data == null) throw new ArgumentNullException("data");
+ if (data.Length == 0) return double.NaN;
var min = double.PositiveInfinity;
for (int i = 0; i < data.Length; i++)
@@ -62,7 +65,8 @@ namespace MathNet.Numerics.Statistics
/// Sample array, no sorting is assumed.
public static double Maximum(double[] data)
{
- if (data == null || data.Length == 0) return double.NaN;
+ if (data == null) throw new ArgumentNullException("data");
+ if (data.Length == 0) return double.NaN;
var max = double.NegativeInfinity;
for (int i = 0; i < data.Length; i++)
@@ -82,7 +86,8 @@ namespace MathNet.Numerics.Statistics
/// Sample array, no sorting is assumed.
public static double Mean(double[] data)
{
- if (data == null || data.Length == 0) return double.NaN;
+ if (data == null) throw new ArgumentNullException("data");
+ if (data.Length == 0) return double.NaN;
double mean = 0;
ulong m = 0;
diff --git a/src/Numerics/Statistics/SortedArrayStatistics.cs b/src/Numerics/Statistics/SortedArrayStatistics.cs
index 76030d79..9cabbd79 100644
--- a/src/Numerics/Statistics/SortedArrayStatistics.cs
+++ b/src/Numerics/Statistics/SortedArrayStatistics.cs
@@ -51,7 +51,9 @@ namespace MathNet.Numerics.Statistics
/// Sample array, must be sorted ascendingly.
public static double Minimum(double[] data)
{
- if (data == null || data.Length == 0) return double.NaN;
+ if (data == null) throw new ArgumentNullException("data");
+ if (data.Length == 0) return double.NaN;
+
return data[0];
}
@@ -61,7 +63,9 @@ namespace MathNet.Numerics.Statistics
/// Sample array, must be sorted ascendingly.
public static double Maximum(double[] data)
{
- if (data == null || data.Length == 0) return double.NaN;
+ if (data == null) throw new ArgumentNullException("data");
+ if (data.Length == 0) return double.NaN;
+
return data[data.Length - 1];
}
@@ -124,7 +128,8 @@ namespace MathNet.Numerics.Statistics
/// Sample array, must be sorted ascendingly.
public static double[] FiveNumberSummary(double[] data)
{
- if (data == null || data.Length == 0) return new[] {double.NaN, double.NaN, double.NaN, double.NaN, double.NaN};
+ if (data == null) throw new ArgumentNullException("data");
+ if (data.Length == 0) return new[] {double.NaN, double.NaN, double.NaN, double.NaN, double.NaN};
return new[] {data[0], Quantile(data, 0.25), Quantile(data, 0.50), Quantile(data, 0.75), data[data.Length - 1]};
}
@@ -142,7 +147,8 @@ namespace MathNet.Numerics.Statistics
///
public static double Quantile(double[] data, double tau)
{
- if (tau < 0d || tau > 1d || data == null || data.Length == 0) return double.NaN;
+ if (data == null) throw new ArgumentNullException("data");
+ if (tau < 0d || tau > 1d || data.Length == 0) return double.NaN;
if (tau == 0d || data.Length == 1) return data[0];
if (tau == 1d) return data[data.Length - 1];
@@ -158,7 +164,8 @@ namespace MathNet.Numerics.Statistics
///
public static double QuantileCompatible(double[] data, double tau, QuantileCompatibility compatibility)
{
- if (tau < 0d || tau > 1d || data == null || data.Length == 0) return double.NaN;
+ if (data == null) throw new ArgumentNullException("data");
+ if (tau < 0d || tau > 1d || data.Length == 0) return double.NaN;
if (tau == 0d || data.Length == 1) return data[0];
if (tau == 1d) return data[data.Length - 1];
diff --git a/src/Numerics/Statistics/StreamingStatistics.cs b/src/Numerics/Statistics/StreamingStatistics.cs
new file mode 100644
index 00000000..057c7e12
--- /dev/null
+++ b/src/Numerics/Statistics/StreamingStatistics.cs
@@ -0,0 +1,82 @@
+//
+// Math.NET Numerics, part of the Math.NET Project
+// http://numerics.mathdotnet.com
+// http://github.com/mathnet/mathnet-numerics
+// http://mathnetnumerics.codeplex.com
+//
+// Copyright (c) 2009-2013 Math.NET
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace MathNet.Numerics.Statistics
+{
+ public static class StreamingStatistics
+ {
+ ///
+ /// Returns the smallest value from the enumerable, in a single pass without memoization.
+ /// Returns NaN if data is empty or any entry is NaN.
+ ///
+ /// Sample stream, no sorting is assumed.
+ public static double Minimum(IEnumerable stream)
+ {
+ if (stream == null) throw new ArgumentNullException("stream");
+
+ var min = double.PositiveInfinity;
+ bool any = false;
+ foreach (double d in stream)
+ {
+ if (d < min || double.IsNaN(d))
+ {
+ min = d;
+ }
+ any = true;
+ }
+ return any ? min : double.NaN;
+ }
+
+ ///
+ /// Returns the largest value from the enumerable, in a single pass without memoization.
+ /// Returns NaN if data is empty or any entry is NaN.
+ ///
+ /// Sample stream, no sorting is assumed.
+ public static double Maximum(IEnumerable stream)
+ {
+ if (stream == null) throw new ArgumentNullException("stream");
+
+ var max = double.NegativeInfinity;
+ bool any = false;
+ foreach (double d in stream)
+ {
+ if (d > max || double.IsNaN(d))
+ {
+ max = d;
+ }
+ any = true;
+ }
+ return any ? max : double.NaN;
+ }
+ }
+}
diff --git a/src/Portable/Portable.csproj b/src/Portable/Portable.csproj
index 784a8c47..dbf23f19 100644
--- a/src/Portable/Portable.csproj
+++ b/src/Portable/Portable.csproj
@@ -1068,6 +1068,9 @@
Statistics\Statistics.cs
+
+ Statistics\StreamingStatistics.cs
+
TargetedPatchingOptOutAttribute.cs
diff --git a/src/UnitTests/StatisticsTests/StatisticsTests.cs b/src/UnitTests/StatisticsTests/StatisticsTests.cs
index a7bb8170..9e924303 100644
--- a/src/UnitTests/StatisticsTests/StatisticsTests.cs
+++ b/src/UnitTests/StatisticsTests/StatisticsTests.cs
@@ -30,7 +30,6 @@
namespace MathNet.Numerics.UnitTests.StatisticsTests
{
-#if !PORTABLE
using System;
using System.Collections.Generic;
using System.IO;
@@ -39,45 +38,79 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
using Statistics;
///
- /// Statistics tests.
+ /// Statistics Tests.
///
- /// NOTE: this class is not included into Silverlight version, because it uses data from local files.
- /// In Silverlight access to local files is forbidden, except several cases.
[TestFixture]
public class StatisticsTests
{
- ///
- /// Statistics data.
- ///
- readonly IDictionary _data = new Dictionary();
+ readonly IDictionary _data = new Dictionary
+ {
+ {"lottery", new StatTestData("./data/NIST/Lottery.dat")},
+ {"lew", new StatTestData("./data/NIST/Lew.dat")},
+ {"mavro", new StatTestData("./data/NIST/Mavro.dat")},
+ {"michelso", new StatTestData("./data/NIST/Michelso.dat")},
+ {"numacc1", new StatTestData("./data/NIST/NumAcc1.dat")},
+ {"numacc2", new StatTestData("./data/NIST/NumAcc2.dat")},
+ {"numacc3", new StatTestData("./data/NIST/NumAcc3.dat")},
+ {"numacc4", new StatTestData("./data/NIST/NumAcc4.dat")}
+ };
- ///
- /// Initializes a new instance of the StatisticsTests class.
- ///
- public StatisticsTests()
+ [Test]
+ public void ThrowsOnNullData()
{
- var lottery = new StatTestData("./data/NIST/Lottery.dat");
- _data.Add("lottery", lottery);
- var lew = new StatTestData("./data/NIST/Lew.dat");
- _data.Add("lew", lew);
- var mavro = new StatTestData("./data/NIST/Mavro.dat");
- _data.Add("mavro", mavro);
- var michelso = new StatTestData("./data/NIST/Michelso.dat");
- _data.Add("michelso", michelso);
- var numacc1 = new StatTestData("./data/NIST/NumAcc1.dat");
- _data.Add("numacc1", numacc1);
- var numacc2 = new StatTestData("./data/NIST/NumAcc2.dat");
- _data.Add("numacc2", numacc2);
- var numacc3 = new StatTestData("./data/NIST/NumAcc3.dat");
- _data.Add("numacc3", numacc3);
- var numacc4 = new StatTestData("./data/NIST/NumAcc4.dat");
- _data.Add("numacc4", numacc4);
+ double[] data = null;
+
+ Assert.Throws(() => Statistics.Minimum(data));
+ Assert.Throws(() => Statistics.Maximum(data));
+ Assert.Throws(() => Statistics.Mean(data));
+
+ Assert.Throws(() => SortedArrayStatistics.Minimum(data));
+ Assert.Throws(() => SortedArrayStatistics.Maximum(data));
+ Assert.Throws(() => SortedArrayStatistics.Median(data));
+ Assert.Throws(() => SortedArrayStatistics.LowerQuartile(data));
+ Assert.Throws(() => SortedArrayStatistics.UpperQuartile(data));
+ Assert.Throws(() => SortedArrayStatistics.Percentile(data, 30));
+ Assert.Throws(() => SortedArrayStatistics.Quantile(data, 0.3));
+ Assert.Throws(() => SortedArrayStatistics.QuantileCompatible(data, 0.3, QuantileCompatibility.Nearest));
+ Assert.Throws(() => SortedArrayStatistics.InterquartileRange(data));
+ Assert.Throws(() => SortedArrayStatistics.FiveNumberSummary(data));
+
+ Assert.Throws(() => ArrayStatistics.Minimum(data));
+ Assert.Throws(() => ArrayStatistics.Maximum(data));
+ Assert.Throws(() => ArrayStatistics.Mean(data));
+
+ Assert.Throws(() => StreamingStatistics.Minimum(data));
+ Assert.Throws(() => StreamingStatistics.Maximum(data));
+ }
+
+ [Test]
+ public void DoesNotThrowOnEmptyData()
+ {
+ double[] data = new double[0];
+
+ //Assert.DoesNotThrow(() => Statistics.Minimum(data));
+ //Assert.DoesNotThrow(() => Statistics.Maximum(data));
+ //Assert.DoesNotThrow(() => Statistics.Mean(data));
+
+ Assert.DoesNotThrow(() => SortedArrayStatistics.Minimum(data));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.Maximum(data));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.Median(data));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.LowerQuartile(data));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.UpperQuartile(data));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.Percentile(data, 30));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.Quantile(data, 0.3));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.QuantileCompatible(data, 0.3, QuantileCompatibility.Nearest));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.InterquartileRange(data));
+ Assert.DoesNotThrow(() => SortedArrayStatistics.FiveNumberSummary(data));
+
+ Assert.DoesNotThrow(() => ArrayStatistics.Minimum(data));
+ Assert.DoesNotThrow(() => ArrayStatistics.Maximum(data));
+ Assert.DoesNotThrow(() => ArrayStatistics.Mean(data));
+
+ Assert.DoesNotThrow(() => StreamingStatistics.Minimum(data));
+ Assert.DoesNotThrow(() => StreamingStatistics.Maximum(data));
}
- ///
- /// Validate mean.
- ///
- /// Dataset name.
[TestCase("lottery")]
[TestCase("lew")]
[TestCase("mavro")]
@@ -86,17 +119,13 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
[TestCase("numacc2")]
[TestCase("numacc3")]
[TestCase("numacc4")]
- public void Mean(string dataSet)
+ public void MeanConsistentWithNistData(string dataSet)
{
var data = _data[dataSet];
AssertHelpers.AlmostEqual(data.Mean, Statistics.Mean(data.Data), 15);
AssertHelpers.AlmostEqual(data.Mean, ArrayStatistics.Mean(data.Data), 15);
}
- ///
- /// Nullable mean.
- ///
- /// Dataset name.
[TestCase("lottery")]
[TestCase("lew")]
[TestCase("mavro")]
@@ -105,22 +134,12 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
[TestCase("numacc2")]
[TestCase("numacc3")]
[TestCase("numacc4")]
- public void NullableMean(string dataSet)
+ public void NullableMeanConsistentWithNistData(string dataSet)
{
var data = _data[dataSet];
AssertHelpers.AlmostEqual(data.Mean, Statistics.Mean(data.DataWithNulls), 15);
}
- ///
- /// Mean with null throws ArgumentNullException.
- ///
- [Test]
- public void MeanThrowsArgumentNullException()
- {
- double[] data = null;
- Assert.Throws(() => Statistics.Mean(data));
- }
-
///
/// Standard Deviation.
///
@@ -227,6 +246,20 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
AssertHelpers.AlmostEqual(2d, Statistics.StandardDeviation(gaussian.Samples().Take(10000)), 2);
}
+ [Test]
+ public void MinimumOfEmptyMustBeNaN()
+ {
+ Assert.That(StreamingStatistics.Minimum(new double[0]), Is.NaN);
+ Assert.That(StreamingStatistics.Minimum(new[] {2d }), Is.Not.NaN);
+ }
+
+ [Test]
+ public void MaximumOfEmptyMustBeNaN()
+ {
+ Assert.That(StreamingStatistics.Maximum(new double[0]), Is.NaN);
+ Assert.That(StreamingStatistics.Maximum(new[] { 2d }), Is.Not.NaN);
+ }
+
[Test]
public void SampleVarianceOfEmptyAndSingleMustBeNaN()
{
@@ -257,5 +290,4 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
Assert.AreEqual(1.0, SortedArrayStatistics.Median(sorted));
}
}
-#endif
}