代码之家  ›  专栏  ›  技术社区  ›  VijayD

无法使用Saxon处理器应用间隔算法

  •  2
  • VijayD  · 技术社区  · 6 年前

    我在用 执行验证。
    包含所有函数定义的文件如下:
    默认定义.txt :

    declare variable $a external; 
    declare variable $b external; 
    declare variable $c external; 
    
    declare function iaf:sum(
    $params as item()*
    ) as item()+ {
    
      let $facts := if (empty($params)) then (0) else one-or-more($params)
      let $values := for $i in $facts return (iaf:splitValueThreshold($i)[1])
      let $thresholds := for $i in $facts return (iaf:splitValueThreshold($i)[2])
      let $sumValues := sum($values)
      let $sumThresholds := sum($thresholds)
      let $output := iaf:joinValueThreshold($sumValues, $sumThresholds) 
           return ($output)
    
    };
    
    declare function iaf:numeric-equal(
    $paramA as item(), $paramB as item()
    ) as xs:boolean {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := abs($itemA[1] - $itemB[1]) le ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:numeric-less-than(
    $paramA as item(), $paramB as item()
    ) as xs:boolean {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := ($itemA[1] - $itemB[1]) lt ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:numeric-less-equal-than(
    $paramA as item(), $paramB as item()
    ) as xs:boolean {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := ($itemA[1] - $itemB[1]) le ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:numeric-greater-than(
    $paramA as item(), $paramB as item()
    ) as xs:boolean {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := $itemA[1] gt ($itemB[1] - ($itemA[2] + $itemB[2])) 
           return ($output)
    
    };
    
    declare function iaf:numeric-greater-equal-than(
    $paramA as item(), $paramB as item()
    ) as xs:boolean {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := $itemA[1] ge ($itemB[1] - ($itemA[2] + $itemB[2])) 
           return ($output)
    
    };
    
    declare function iaf:numeric-add(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $value := $itemA[1]+$itemB[1]
      let $threshold := $itemA[2]+$itemB[2]
      let $output := iaf:joinValueThreshold($value,$threshold) 
           return ($output)
    
    };
    
    declare function iaf:numeric-subtract(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $value := $itemA[1]-$itemB[1]
      let $threshold := $itemA[2]+$itemB[2]
      let $output := iaf:joinValueThreshold($value,$threshold) 
           return ($output)
    
    };
    
    declare function iaf:numeric-divide(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $A := $itemA[1]
      let $B := $itemB[1]
      let $deltaA := $itemA[2]
      let $deltaB := $itemB[2]
      let $AdivB := $A div $B
      let $J0 := ($A + $deltaA) div ($B + $deltaB)
      let $J1 := ($A + $deltaA) div ($B - $deltaB)
      let $J2 := ($A - $deltaA) div ($B + $deltaB)
      let $J3 := ($A - $deltaA) div ($B - $deltaB)
      let $threshold := max((abs($AdivB - $J0), abs($AdivB - $J1), abs($AdivB - $J2), abs($AdivB - $J3)))
      let $output := iaf:joinValueThreshold($AdivB, $threshold) 
           return ($output)
    
    };
    
    declare function iaf:numeric-multiply(
    $paramA as item(), $paramB as item()
    ) as item() {
      iaf:multiply-two-elements($paramA, $paramB)
    };
    
    declare function iaf:numeric-multiply(
    $params as item()+
    ) as item() {
    
      let $output := iaf:multiply-recursive($params, 1, 0) 
           return ($output)
    
    };
    
    declare function iaf:abs(
    $input as item()
    ) as item() {
    
      let $item := if (empty($input)) then 0 else $input
      let $output := if ($item instance of element() and empty($item[2])) then
        iaf:joinValueThreshold(abs($item), iaf-int:fact-threshold($item)) else (if (not($item instance of
        element()) and empty($item[2]) and not(contains(string($item), ";"))) then
        iaf:joinValueThreshold(abs($item), 0) else
        iaf:joinValueThreshold(abs(xs:decimal(substring-before($item, ";"))),
        xs:decimal(substring-after($item, ";"))))  
           return ($output)
    
    };
    
    declare function iaf:numeric-unary-minus(
    $item as item()
    ) as item() {
    
      let $output := if ($item instance of element() and empty($item[2])) then
        iaf:joinValueThreshold(-($item), iaf-int:fact-threshold($item)) else (if (not($item instance of
        element()) and empty($item[2]) and not(contains(string($item), ";"))) then
        iaf:joinValueThreshold(-($item), 0) else
        iaf:joinValueThreshold(-(xs:decimal(substring-before($item, ";"))),
        xs:decimal(substring-after($item, ";"))))  
           return ($output)
    
    };
    
    declare function iaf:min(
    $params as item()*
    ) as item() {
    
      let $facts := if (empty($params)) then (0) else one-or-more($params)
      let $values := for $i in $facts return (iaf:splitValueThreshold($i)[1])
      let $thresholds := for $i in $facts return (iaf:splitValueThreshold($i)[2])
      let $minValue := min($values)
      let $indexMin := index-of($values, $minValue)[1]
      let $minThreshold := $thresholds[$indexMin]
      let $output := iaf:joinValueThreshold($minValue,$minThreshold) 
           return ($output)
    
    };
    
    declare function iaf:max(
    $params as item()*
    ) as item() {
    
      let $facts := if (empty($params)) then (0) else one-or-more($params)
      let $values := for $i in $facts return (iaf:splitValueThreshold($i)[1])
      let $thresholds := for $i in $facts return (iaf:splitValueThreshold($i)[2])
      let $maxValue := max($values)
      let $indexMax := index-of($values, $maxValue)[1]
      let $maxThreshold := $thresholds[$indexMax]
      let $output := iaf:joinValueThreshold($maxValue,$maxThreshold) 
           return ($output)
    
    };
    
    declare function iaf:splitValueThreshold(
    $item as item()
    ) as item()+ {
    
      let $valorUmbral := if ($item instance of element() and empty($item[2])) then ($item,
        iaf-int:fact-threshold($item)) else (if (not($item instance of element()) and empty($item[2])
        and not(contains(string($item), ";"))) then ($item, 0) else
        (xs:decimal(substring-before($item, ";")), xs:decimal(substring-after($item, ";"))))  
           return ($valorUmbral)
    
    };
    
    declare function iaf:joinValueThreshold(
    $value as item(), $threshold as item()
    ) as xs:string {
    
      let $output := concat(string($value),";",string($threshold)) 
           return ($output)
    
    };
    
    declare function iaf:precision(
    $item as item()+
    ) as xs:decimal {
    
      let $ouput := xfi:decimals($item) 
           return ($ouput)
    
    };
    
    declare function iaf:multiply-recursive(
    $sequence as item()+, $count as item(), $subtotalParam as item()
    ) as item() {
    
      let $facts := if (empty($sequence)) then (0) else
        one-or-more($sequence)
      let $numberOfParams := count($facts)
      let $subtotal := if ($count eq 1) then $facts[1] else $subtotalParam
      let $multiply := if($count lt $numberOfParams) then iaf:multiply-two-elements($subtotal,
        $facts[$count + 1]) else $subtotal
      let $output := if($count lt $numberOfParams) then iaf:multiply-recursive($sequence,
        ($count +1), $multiply) else $multiply 
           return ($output)
    
    };
    
    declare function iaf:multiply-two-elements(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $A := $itemA[1]
      let $B := $itemB[1]
      let $deltaA := $itemA[2]
      let $deltaB := $itemB[2]
      let $AxB := $A * $B
      let $threshold := sum((abs($A * $deltaB), abs($B * $deltaA), $deltaA * $deltaB)) 
           return (iaf:joinValueThreshold($AxB, $threshold))
    
    };
    
    declare function iaf:numeric-equal-threshold(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:numeric-less-than-threshold(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:numeric-less-equal-than-threshold(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:numeric-greater-than-threshold(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:numeric-greater-equal-than-threshold(
    $paramA as item(), $paramB as item()
    ) as item() {
    
      let $itemA := iaf:splitValueThreshold($paramA)
      let $itemB := iaf:splitValueThreshold($paramB)
      let $output := ($itemA[2] + $itemB[2]) 
           return ($output)
    
    };
    
    declare function iaf:abs-sequence(
    $params as item()*
    ) as item()+ {
    
      let $facts := if (empty($params)) then (0) else one-or-more($params)
      let $values := for $i in $facts return (iaf:abs($i)) 
           return (($values))
    
    };
    
    declare function iaf:numeric-equal-test(
    $paramA as item(), $paramB as item()
    ) as item()+ {
    
      let $valueA := iaf:splitValueThreshold($paramA)[1]
      let $valueB := iaf:splitValueThreshold($paramB)[1]
      let $thA := iaf:splitValueThreshold($paramA)[2]
      let $thB := iaf:splitValueThreshold($paramB)[2]
      let $absol := abs($valueA - $valueB)
      let $sumTh := $thA + $thB 
           return (($valueA, $valueB, $thA, $thB, $absol, $sumTh))
    
    };
    
    declare function iaf-int:exp10(
    $power as xs:integer
    ) as xs:decimal {
      if ($power eq 0) then 1 else if ($power gt 0) then 10 * iaf-int:exp10($power - 1) else 1 div iaf-int:exp10(-$power)
    };
    
    declare function iaf-int:fact-threshold(
    $fact as item()
    ) as xs:decimal {
    
      let $decimals := xfi:decimals($fact) 
           return (if (string($decimals) = 'INF') then 0 else iaf-int:exp10(-xs:integer($decimals)) div 2)
    
    };
    declare function xff:has-fallback-value(
    $fact as xs:QName
    ) as xs:boolean{
                let $result := if (string($a) = '') then fn:true() else fn:false()
                return ($result)
    };
    declare function xfi:decimals($fact as item() ) as item()+ { let $deci := $fact/@decimals  return ($deci)};
    declare function xfi:fact-typed-dimension-value($fact as item() , $typedDim as xs:QName?) as xs:string {let $dimName := substring-before(substring-after($fact,concat("s2c_dim:",$typedDim,"__TDVALUE__")),";") return ($dimName)};
    $a = +$b + $c
    

    :

    XdmValue xqueryResult = null;
    XQueryCompiler xqueryCompiler = new Processor(false).newXQueryCompiler();
    declareNamespace(xqueryCompiler);
    XQueryExecutable queryExecutable = xqueryCompiler.compile(new File("default-definition.txt")); //I18NOK:LSM
    XQueryEvaluator xqueryEvaluator = queryExecutable.load();
    double aa=331640738.91;
    double bb=393432239.2;
    double cc=-61791500.29;
    
    //previous strategy, which is now throwing an exception
    //  XPTY0004: Cannot compare xs:string to xs:double
    xqueryEvaluator.setExternalVariable(new QName("a"), new XdmAtomicValue(String.format("%s;%s", aa,FactValue.getPrecision("-3"))));
    xqueryEvaluator.setExternalVariable(new QName("b"), new XdmAtomicValue(bb));
    xqueryEvaluator.setExternalVariable(new QName("c"), new XdmAtomicValue(cc));
    xqueryEvaluator.toString();
    xqueryResult = xqueryEvaluator.evaluate();
    System.out.println(Boolean.valueOf(xqueryResult.itemAt(0).getStringValue()));
    
    //exact match --Result: FAIL
    xqueryEvaluator.setExternalVariable(new QName("a"), new XdmAtomicValue(aa));
    xqueryEvaluator.setExternalVariable(new QName("b"), new XdmAtomicValue(bb));
    xqueryEvaluator.setExternalVariable(new QName("c"), new XdmAtomicValue(cc));
    xqueryEvaluator.toString();
    xqueryResult = xqueryEvaluator.evaluate();
    System.out.println(Boolean.valueOf(xqueryResult.itemAt(0).getStringValue()));
    
    //matching after rounding off till the range of 1000 --Result: FAIL
    double a = Math.round(Double.parseDouble("331640738.91") * Math.pow(10,-3)) / Math.pow(10,-3);
    double b = Math.round(Double.parseDouble("393432239.2") * Math.pow(10,-3)) / Math.pow(10,-3);
    double c = Math.round(Double.parseDouble("-61791500.29") * Math.pow(10,-3)) / Math.pow(10,-3);
    
    xqueryEvaluator.setExternalVariable(new QName("a"), new XdmAtomicValue(a));
    xqueryEvaluator.setExternalVariable(new QName("b"), new XdmAtomicValue(b));
    xqueryEvaluator.setExternalVariable(new QName("c"), new XdmAtomicValue(c));
    xqueryEvaluator.toString();
    xqueryResult = xqueryEvaluator.evaluate();
    System.out.println(Boolean.valueOf(xqueryResult.itemAt(0).getStringValue()));
    

    理想情况下,“a”和“b+c”的值之间的差别是小数,应该可以忽略。请让我知道是否有其他方法可以使用Saxon执行间隔算术。

    谢谢!

    1 回复  |  直到 6 年前
        1
  •  5
  •   Michael Kay    6 年前

    如果添加断言

    assertEquals(aa, bb+cc);
    

    在声明这些变量之后,您将看到Java代码失败:

    Expected (aa) :3.3164073891E8
    Actual(bb+cc) :3.3164073890999997E8 
    

    失败是因为舍入错误将您写入的值(如331640738.91)转换为在双精度值空间内可表示的最接近值。

    如果要使用精确的十进制算法,则需要使用 xs:decimal 数据类型而不是 xs:double