pdf-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [pdf-devel] Type 4 functions


From: Johannes Tax
Subject: Re: [pdf-devel] Type 4 functions
Date: Sat, 9 Jan 2010 13:21:57 +0100
User-agent: Mutt/1.5.19 (2009-01-05)

Hi,

On [Wed, 06.01.2010 23:04], address@hidden wrote:
> [...]
>
> could work, yielding the boolean values in the stack.  But it is not
> clear what would happen with a function like:
> 
>    { true true and }
> 
> With the current implementation and the above hack, the result on the
> stack would be something like 1.202057, that is the float
> interpretation of the internal representation of 'true'
> (PDF_FP_FUNC_TYPE4_TRUE).
> 
> On the other hand, the spec is clear in that the range of the pdf
> functions is a real interval, so I suppose that the above function
> shall be considered invalid.

I think so too. Furthermore the current implementation allows something
like { true true and 1 add }, which is clearly invalid (the ghostscript
interpreter raises a type exception).

It seems that the PDF spec requires a stricter type checking than is
currently implemented. The mod operator for example is defined to take
two integer arguments. So { 10.0 3.0 mod } should be invalid (and is
treated as such by gs) but it is not treated as such by the current 
implementation.

Treating this correctly would require attaching a type to every element
on the stack, I think something like

struct stack_element_t {
  enum type { BOOL, INT, REAL } t;
  double v;
} stack[NSTACK+2];

and a set of suitable predicates/accessors would do the job, some
additional checks for numerical constants and return values would be
required too. I don't know if this is considered neccessary. As far as 
I can see the current approach works well for all valid type 4 functions.
However, it also treats obviously invalid type 4 functions as valid ones.
I don't think that fixing this requires too much effort.

> [...]
> 
> Actually what we need are systematic tests on every allowed operator.
> For each operator, would be good to have:
> 
> - A couple of positive tests (with valid values in the domain).
> - A couple of negative tests, if applicable (with invalid values in
>   the domain).
> - A couple of extreme/interesting cases tests, if applicable.

Please find attached some first tests I have written 
(torture/unit/base/fp/pdf-fp-func-eval.c) and the required changes to 
pass them (src/base/pdf-fp-func.c). The changes concern the following 
issues:

1) Input values are not clipped to the domain.
2) The second operand to mod must not be 0. I suppose in this case
setting PDF_EMATH as appropriate.
3) It is a range error to pass a negative value to the log functions. I 
think passing 0 should cause a range error too.

I will go on writing tests in this manner.

Regards,
Johannes

-- 
Johannes Tax
address@hidden


=== modified file 'src/base/pdf-fp-func.c'
--- src/base/pdf-fp-func.c      2009-06-17 19:42:48 +0000
+++ src/base/pdf-fp-func.c      2010-01-09 10:45:37 +0000
@@ -1439,7 +1439,7 @@
 
   for (sp = 0; sp < t->m; sp++)
     {
-      stack[sp] = in[sp];
+      stack[sp] = clip(in[sp], t->domain + 2*sp);
     }
   sp--;
   for (pc = 0; pc < n; pc++)
@@ -1515,7 +1515,7 @@
           break;
         case OPC_log:
           if (sp < 0) goto stack_underflow;
-          if (stack[sp] < 0) goto range_error;
+          if (stack[sp] <= 0) goto range_error;
           stack[sp] = pdf_fp_log10 (stack[sp]);
           break;
         case OPC_ln:
@@ -1642,6 +1642,8 @@
           if (sp < 1) goto stack_underflow;
           if (!INT_P(stack[sp]) || !INT_P(stack[sp-1]))
             goto type_error;
+          if (stack[sp-1] == 0)
+            goto math_error;
           stack[sp-1] = INT(stack[sp]) % INT(stack[sp-1]);
           sp--;
           break;

=== modified file 'torture/unit/base/fp/pdf-fp-func-eval.c'
--- torture/unit/base/fp/pdf-fp-func-eval.c     2009-08-05 20:32:56 +0000
+++ torture/unit/base/fp/pdf-fp-func-eval.c     2010-01-09 10:47:46 +0000
@@ -1848,6 +1848,171 @@
 END_TEST
 
 
+/*
+ * Test: pdf_fp_func_eval_025
+ * Description:
+ *   Evaluate a type 4 function that uses the mod operator.
+ * Success condition:
+ *   The result of the evaluations should be correct.
+ */
+static pdf_real_t
+mod_f (pdf_real_t x, pdf_real_t y)
+{
+    return (int)x %  (int)y;
+}
+START_TEST(pdf_fp_func_eval_025)
+{
+  pdf_fp_func_t func;
+  pdf_fp_func_debug_t debug;
+  pdf_size_t prog_size;
+  pdf_char_t *prog =
+    "{ "
+    " mod"
+    "}" ;
+
+  pdf_real_t domain[4] = {-10.0, 10.0, -10.0, 10.0};
+  pdf_real_t range[2] = {-10.0, 10.0};
+  pdf_real_t in[2];
+  pdf_real_t out[1];
+
+  prog_size = strlen (prog);
+
+  pdf_init();
+
+  /* Create the function */
+  fail_if(pdf_fp_func_4_new (2, 1,
+                             domain,
+                             range,
+                             prog,
+                             prog_size,
+                             NULL,
+                             &func) != PDF_OK);
+
+  /*
+   * Eval for some values
+   */
+
+  /* x = 1, y = 0 
+   * math error -  division by 0 */
+  in[0] = 0;
+  in[1] = 1;
+  fail_if(pdf_fp_func_eval (func, in, out, &debug) != PDF_ETYPE4);
+  fail_if(debug.type4.status != PDF_EMATH);
+
+  /* x = 5, y = 3.5 
+   * type error - real number argument to mod */
+  in[0] = 3.5;
+  in[1] = 5;
+  fail_if(pdf_fp_func_eval (func, in, out, &debug) != PDF_ETYPE4);
+  fail_if(debug.type4.status != PDF_EBADTYPE);
+
+  /* x = 9.3, y = 3 
+   * type error - real number argument to mod */
+  in[0] = 3;
+  in[1] = 9.3;
+  fail_if(pdf_fp_func_eval (func, in, out, &debug) != PDF_ETYPE4);
+  fail_if(debug.type4.status != PDF_EBADTYPE);
+
+  /* x = 0, y = 1 */
+  in[0] = 1;
+  in[1] = 0;
+  fail_if(pdf_fp_func_eval (func, in, out, NULL) != PDF_OK);
+  fail_if(pdf_fp_abs(out[0] - mod_f(in[1], in[0])) > ABS_ERROR);
+
+  /* x = 5, y = 3 */
+  in[0] = 3;
+  in[1] = 5;
+  fail_if(pdf_fp_func_eval (func, in, out, NULL) != PDF_OK);
+  fail_if(pdf_fp_abs(out[0] - mod_f(in[1], in[0])) > ABS_ERROR);
+
+  /* x = 12, y = 7
+   * x out of (positive) domain */
+  in[0] = 7;
+  in[1] = 12;
+  fail_if(pdf_fp_func_eval (func, in, out, NULL) != PDF_OK);
+  fail_if(pdf_fp_abs(out[0] - mod_f(domain[1], in[0])) > ABS_ERROR);
+}
+END_TEST
+
+
+/*
+ * Test: pdf_fp_func_eval_026
+ * Description:
+ *   Evaluate a type 4 function that uses the log operator.
+ * Success condition:
+ *   The result of the evaluations should be correct.
+ */
+static pdf_real_t
+log_f (pdf_real_t x)
+{
+    return pdf_fp_log10(x);
+}
+START_TEST(pdf_fp_func_eval_026)
+{
+  pdf_fp_func_t func;
+  pdf_fp_func_debug_t debug;
+  pdf_size_t prog_size;
+  pdf_char_t *prog =
+    "{ "
+    " log"
+    "}" ;
+
+  pdf_real_t domain[2] = {-20.0, 20.0};
+  pdf_real_t range[2] = {-1.0, 1.0};
+  pdf_real_t in[1];
+  pdf_real_t out[1];
+
+  prog_size = strlen (prog);
+
+  pdf_init();
+
+  /* Create the function */
+  fail_if(pdf_fp_func_4_new (1, 1,
+                             domain,
+                             range,
+                             prog,
+                             prog_size,
+                             NULL, 
+                             &func) != PDF_OK);
+
+  /*
+   * Eval for some values
+   */
+
+  /* x = -1 
+   * invalid range error - log of negative number */
+  in[0] = -1;
+  fail_if(pdf_fp_func_eval (func, in, out, &debug) != PDF_ETYPE4);
+  fail_if(debug.type4.status != PDF_EINVRANGE);
+
+  /* x = 0 *
+   * invalid range error - log of 0 */
+  in[0] = 0;
+  fail_if(pdf_fp_func_eval (func, in, out, &debug) != PDF_ETYPE4);
+  fail_if(debug.type4.status != PDF_EINVRANGE);
+
+  /* x = 1 */
+  in[0] = 1;
+  fail_if(pdf_fp_func_eval (func, in, out, NULL) != PDF_OK);
+  fail_if(pdf_fp_abs(out[0] - log_f(in[0])) > ABS_ERROR);
+
+  /* x = 1.533 */
+  in[0] = 1.533; 
+  fail_if(pdf_fp_func_eval (func, in, out, NULL) != PDF_OK);
+  fail_if(pdf_fp_abs(out[0] - log_f(in[0])) > ABS_ERROR);
+
+  /* x = 9 */
+  in[0] = 9;
+  fail_if(pdf_fp_func_eval (func, in, out, NULL) != PDF_OK);
+  fail_if(pdf_fp_abs(out[0] - log_f(in[0])) > ABS_ERROR);
+
+  /* x = 14
+   * result out of (positive) range */
+  in[0] = 14;
+  fail_if(pdf_fp_func_eval (func, in, out, NULL) != PDF_OK);
+  fail_if(pdf_fp_abs(out[0] - range[1]) > ABS_ERROR);
+}
+END_TEST
 
 
 
@@ -1883,6 +2048,8 @@
   tcase_add_test(tc, pdf_fp_func_eval_022);
   tcase_add_test(tc, pdf_fp_func_eval_023);
   tcase_add_test(tc, pdf_fp_func_eval_024);
+  tcase_add_test(tc, pdf_fp_func_eval_025);
+  tcase_add_test(tc, pdf_fp_func_eval_026);
 
   return tc;
 }





reply via email to

[Prev in Thread] Current Thread [Next in Thread]