psppire-dialog: Fix incompatible pointer type.
[pspp] / src / math / histogram.c
index 7fc2d08e3de341a49455e0395d7283e204384f79..3c324eff2485d583c3cff0c72e49c137c98aecca 100644 (file)
 #include <config.h>
 
 #include "math/histogram.h"
+#include "math/decimal.h"
 
 #include <gsl/gsl_histogram.h>
 #include <math.h>
 
+#include "data/settings.h"
 #include "libpspp/message.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
@@ -84,6 +86,10 @@ double get_slack (double limit, double half_bin_width, int *n_half_bins)
    ADJ_MIN and ADJ_MAX are locations of the adjusted values of MIN and MAX (the range will
    always be  equal or slightly larger).
    Returns the number of bins.
+
+   The "testing_assert" expressions in this function should be algebraically correct.
+   However, due to floating point rounding they could fail, especially when small numbers
+   are involved.  In normal use, therefore, testing_assert does nothing.
  */
 static int
 adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, double *adj_max)
@@ -97,7 +103,7 @@ adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, do
   double lower_slack =  get_slack (min, half_bin_width, &lower_limit);
   double upper_slack = -get_slack (max, half_bin_width, &upper_limit);
 
-  assert (max > min);
+  testing_assert (max > min);
 
   /* If min is negative, then lower_slack may be less than zero.
      In this case, the lower bound must be extended in the negative direction
@@ -108,7 +114,7 @@ adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, do
       lower_limit--;
       lower_slack += half_bin_width;
     }
-  assert (lower_limit * half_bin_width <= min);
+  testing_assert (lower_limit * half_bin_width <= min);
 
   /* However, the upper bound must be extended regardless, because histogram bins
      span the range [lower, upper). In other words, the upper bound must be
@@ -116,7 +122,7 @@ adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, do
   */
   upper_limit++;;
   upper_slack += half_bin_width;
-  assert (upper_limit * half_bin_width > max);
+  testing_assert (upper_limit * half_bin_width > max);
 
   /* The range must be an EVEN number of half bin_widths */
   if ( (upper_limit - lower_limit) % 2)
@@ -159,7 +165,7 @@ adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, do
 
       if (upper_slack > lower_slack)
         {
-          assert (upper_slack > half_bin_width);
+          testing_assert (upper_slack > half_bin_width);
 
           /* Adjust the range to the left */
           lower_limit --;
@@ -169,7 +175,7 @@ adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, do
         }
       else
         {
-          assert (lower_slack >= half_bin_width);
+          testing_assert (lower_slack >= half_bin_width);
 
           /* Adjust the range to the right */
           lower_limit ++;
@@ -197,8 +203,8 @@ adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, do
   *adj_min = lower_limit * half_bin_width;
   *adj_max = upper_limit * half_bin_width;
 
-  assert (*adj_max > max);
-  assert (*adj_min <= min);
+  testing_assert (*adj_max > max);
+  testing_assert (*adj_min <= min);
 
   return (upper_limit - lower_limit) / 2.0;
 }
@@ -206,8 +212,9 @@ adjust_bin_ranges (double bin_width, double min, double max, double *adj_min, do
 
 
 struct histogram *
-histogram_create (double bin_width, double min, double max)
+histogram_create (double bin_width_in, double min, double max)
 {
+  struct decimal bin_width;
   const int MAX_BINS = 25;
   struct histogram *h;
   struct statistic *stat;
@@ -220,14 +227,17 @@ histogram_create (double bin_width, double min, double max)
       return NULL;
     }
 
-  assert (bin_width > 0);
+  assert (bin_width_in > 0);
 
-  bins = adjust_bin_ranges (bin_width, min, max, &adjusted_min, &adjusted_max);
+  chart_rounded_tick (bin_width_in, &bin_width);
+  bins = adjust_bin_ranges (decimal_to_double (&bin_width), 
+                           min, max, &adjusted_min, &adjusted_max);
 
   /* Force the number of bins to lie in a sensible range. */
   if (bins > MAX_BINS) 
     {
-      bins = adjust_bin_ranges ((max - min) / (double) (MAX_BINS - 1),
+      chart_rounded_tick ((max - min) / (double) (MAX_BINS - 1), &bin_width);
+      bins = adjust_bin_ranges (decimal_to_double (&bin_width),
                                 min, max, &adjusted_min, &adjusted_max);
     }