2323#include < algorithm>
2424#include < cassert>
2525#include < cmath>
26+ #include < expected>
2627#include < numeric>
2728
2829namespace
@@ -148,13 +149,13 @@ void RigStatisticsMath::calculateStatisticsCurves( const std::vector<double>& va
148149
149150 // Use the vector-based implementation
150151 std::vector<double > percentiles = { 0.1 , 0.5 , 0.9 };
151- std::vector< double > results = calculatePercentiles ( values, percentiles, percentileStyle );
152+ auto results = calculatePercentiles ( values, percentiles, percentileStyle );
152153
153- if ( results.size () == 3 )
154+ if ( results.has_value () && results-> size () == 3 )
154155 {
155- *p10 = results[0 ];
156- *p50 = results[1 ];
157- *p90 = results[2 ];
156+ *p10 = ( * results ) [0 ];
157+ *p50 = ( * results ) [1 ];
158+ *p90 = ( * results ) [2 ];
158159 }
159160 else
160161 {
@@ -198,14 +199,24 @@ void RigStatisticsMath::calculateStatisticsCurves( const std::vector<double>& va
198199// / https://en.wikipedia.org/wiki/Percentile
199200// / https://en.wikipedia.org/wiki/Percentile#Third_variant,_C_=_0
200201// --------------------------------------------------------------------------------------------------
201- std::vector<double > RigStatisticsMath::calculatePercentiles ( const std::vector<double >& values,
202- const std::vector<double >& quantiles,
203- PercentileStyle percentileStyle )
202+ std::expected<std:: vector<double >, std::string > RigStatisticsMath::calculatePercentiles ( const std::vector<double >& values,
203+ const std::vector<double >& quantiles,
204+ PercentileStyle percentileStyle )
204205{
205- CVF_ASSERT ( areValidQuantiles ( quantiles ) && " Quantiles must be in range [0-1]" );
206+ if ( !areValidQuantiles ( quantiles ) )
207+ {
208+ return std::unexpected ( " Quantiles must be in range [0-1]" );
209+ }
206210
207- std::vector<double > resultValues;
208- if ( values.empty () || quantiles.empty () ) return resultValues;
211+ if ( values.empty () )
212+ {
213+ return std::unexpected ( " Input values are empty" );
214+ }
215+
216+ if ( quantiles.empty () )
217+ {
218+ return std::unexpected ( " Quantiles are empty" );
219+ }
209220
210221 std::vector<double > sortedValues = values;
211222
@@ -214,11 +225,15 @@ std::vector<double> RigStatisticsMath::calculatePercentiles( const std::vector<d
214225 []( double x ) { return !RiaStatisticsTools::isValidNumber ( x ); } ),
215226 sortedValues.end () );
216227
217- if ( sortedValues.empty () ) return resultValues;
228+ if ( sortedValues.empty () )
229+ {
230+ return std::unexpected ( " No valid values in input" );
231+ }
218232
219233 std::sort ( sortedValues.begin (), sortedValues.end () );
220234
221- int valueCount = (int )sortedValues.size ();
235+ int valueCount = (int )sortedValues.size ();
236+ std::vector<double > resultValues;
222237 resultValues.reserve ( quantiles.size () );
223238
224239 for ( size_t i = 0 ; i < quantiles.size (); ++i )
@@ -273,11 +288,25 @@ std::vector<double> RigStatisticsMath::calculatePercentiles( const std::vector<d
273288// / https://en.wikipedia.org/wiki/Percentile#First_variant,_C_=_1/2
274289// --------------------------------------------------------------------------------------------------
275290
276- std::vector<double > RigStatisticsMath::calculateNearestRankPercentiles ( const std::vector<double >& inputValues,
277- const std::vector<double >& percentiles,
278- RigStatisticsMath::PercentileStyle percentileStyle )
291+ std::expected<std::vector<double >, std::string>
292+ RigStatisticsMath::calculateNearestRankPercentiles ( const std::vector<double >& inputValues,
293+ const std::vector<double >& percentiles,
294+ RigStatisticsMath::PercentileStyle percentileStyle )
279295{
280- CVF_ASSERT ( areValidPercentiles ( percentiles ) && " Percentiles must be in range [0-100]" );
296+ if ( !areValidPercentiles ( percentiles ) )
297+ {
298+ return std::unexpected ( " Percentiles must be in range [0-100]" );
299+ }
300+
301+ if ( inputValues.empty () )
302+ {
303+ return std::unexpected ( " Input values are empty" );
304+ }
305+
306+ if ( percentiles.empty () )
307+ {
308+ return std::unexpected ( " Percentiles are empty" );
309+ }
281310
282311 std::vector<double > sortedValues;
283312 sortedValues.reserve ( inputValues.size () );
@@ -290,27 +319,29 @@ std::vector<double> RigStatisticsMath::calculateNearestRankPercentiles( const st
290319 }
291320 }
292321
322+ if ( sortedValues.empty () )
323+ {
324+ return std::unexpected ( " No valid values in input" );
325+ }
326+
293327 std::sort ( sortedValues.begin (), sortedValues.end () );
294328
295329 std::vector<double > resultValues ( percentiles.size (), HUGE_VAL );
296- if ( !sortedValues. empty () )
330+ for ( size_t i = 0 ; i < percentiles. size (); ++i )
297331 {
298- for ( size_t i = 0 ; i < percentiles.size (); ++i )
299- {
300- double quantile = cvf::Math::abs ( percentiles[i] ) / 100 ;
301- if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
332+ double quantile = cvf::Math::abs ( percentiles[i] ) / 100 ;
333+ if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
302334
303- size_t index = static_cast <size_t >( sortedValues.size () * quantile );
335+ size_t index = static_cast <size_t >( sortedValues.size () * quantile );
304336
305- if ( index >= sortedValues.size () ) index = sortedValues.size () - 1 ;
337+ if ( index >= sortedValues.size () ) index = sortedValues.size () - 1 ;
306338
307- auto value = sortedValues[index];
308- resultValues[i] = value;
309- }
339+ auto value = sortedValues[index];
340+ resultValues[i] = value;
310341 }
311342
312343 return resultValues;
313- };
344+ }
314345
315346// --------------------------------------------------------------------------------------------------
316347// / Calculate the percentiles of /a inputValues at the pValPosition percentages by interpolating input values.
@@ -331,11 +362,25 @@ std::vector<double> RigStatisticsMath::calculateNearestRankPercentiles( const st
331362// / https://en.wikipedia.org/wiki/Percentile#The_linear_interpolation_between_closest_ranks_method
332363// / https://en.wikipedia.org/wiki/Percentile#Second_variant,_C_=_1
333364// --------------------------------------------------------------------------------------------------
334- std::vector<double > RigStatisticsMath::calculateInterpolatedPercentiles ( const std::vector<double >& inputValues,
335- const std::vector<double >& percentiles,
336- RigStatisticsMath::PercentileStyle percentileStyle )
365+ std::expected<std::vector<double >, std::string>
366+ RigStatisticsMath::calculateInterpolatedPercentiles ( const std::vector<double >& inputValues,
367+ const std::vector<double >& percentiles,
368+ RigStatisticsMath::PercentileStyle percentileStyle )
337369{
338- CVF_ASSERT ( areValidPercentiles ( percentiles ) && " Percentiles must be in range [0-100]" );
370+ if ( !areValidPercentiles ( percentiles ) )
371+ {
372+ return std::unexpected ( " Percentiles must be in range [0-100]" );
373+ }
374+
375+ if ( inputValues.empty () )
376+ {
377+ return std::unexpected ( " Input values are empty" );
378+ }
379+
380+ if ( percentiles.empty () )
381+ {
382+ return std::unexpected ( " Percentiles are empty" );
383+ }
339384
340385 std::vector<double > sortedValues;
341386 sortedValues.reserve ( inputValues.size () );
@@ -348,36 +393,38 @@ std::vector<double> RigStatisticsMath::calculateInterpolatedPercentiles( const s
348393 }
349394 }
350395
396+ if ( sortedValues.empty () )
397+ {
398+ return std::unexpected ( " No valid values in input" );
399+ }
400+
351401 std::sort ( sortedValues.begin (), sortedValues.end () );
352402
353403 std::vector<double > resultValues ( percentiles.size (), HUGE_VAL );
354- if ( !sortedValues. empty () )
404+ for ( size_t i = 0 ; i < percentiles. size (); ++i )
355405 {
356- for ( size_t i = 0 ; i < percentiles.size (); ++i )
357- {
358- double value = HUGE_VAL;
406+ double value = HUGE_VAL;
359407
360- double quantile = cvf::Math::abs ( percentiles[i] ) / 100.0 ;
361- if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
408+ double quantile = cvf::Math::abs ( percentiles[i] ) / 100.0 ;
409+ if ( percentileStyle == RigStatisticsMath::PercentileStyle::SWITCHED ) quantile = 1.0 - quantile;
362410
363- double doubleIndex = ( sortedValues.size () - 1 ) * quantile;
411+ double doubleIndex = ( sortedValues.size () - 1 ) * quantile;
364412
365- size_t lowerValueIndex = static_cast <size_t >( floor ( doubleIndex ) );
366- size_t upperValueIndex = lowerValueIndex + 1 ;
413+ size_t lowerValueIndex = static_cast <size_t >( floor ( doubleIndex ) );
414+ size_t upperValueIndex = lowerValueIndex + 1 ;
367415
368- double upperValueWeight = doubleIndex - lowerValueIndex;
369- assert ( upperValueWeight < 1.0 );
416+ double upperValueWeight = doubleIndex - lowerValueIndex;
417+ assert ( upperValueWeight < 1.0 );
370418
371- if ( upperValueIndex < sortedValues.size () )
372- {
373- value = ( 1.0 - upperValueWeight ) * sortedValues[lowerValueIndex] + upperValueWeight * sortedValues[upperValueIndex];
374- }
375- else
376- {
377- value = sortedValues[lowerValueIndex];
378- }
379- resultValues[i] = value;
419+ if ( upperValueIndex < sortedValues.size () )
420+ {
421+ value = ( 1.0 - upperValueWeight ) * sortedValues[lowerValueIndex] + upperValueWeight * sortedValues[upperValueIndex];
422+ }
423+ else
424+ {
425+ value = sortedValues[lowerValueIndex];
380426 }
427+ resultValues[i] = value;
381428 }
382429
383430 return resultValues;
0 commit comments