001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2006-2012 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap.fun; 011 012import mondrian.calc.*; 013import mondrian.calc.impl.AbstractDoubleCalc; 014import mondrian.mdx.ResolvedFunCall; 015import mondrian.olap.*; 016 017/** 018 * Definition of the <code>Percentile</code> MDX function. 019 * 020 * <p>There is some discussion about what the "right" percentile function is. 021 * Here is a <a href="http://cnx.org/content/m10805/latest/">good overview</a>. 022 * Wikipedia also lists 023 * <a href="http://en.wikipedia.org/wiki/Percentile">another method</a>: 024 * 025 * <blockquote>rank = P / 100 * (N - 1) + 1</blockquote> 026 * 027 * <p>Implemented here is example 1 on that page, except we use</p> 028 * 029 * <blockquote>rank = P / 100 * N</blockquote> 030 * 031 * <p>for the rank instead of</p> 032 * 033 * <blockquote>rank = P / 100 * (N + 1)</blockquote> 034 * 035 * <p>That's because this is how it used to be in the code.</p> 036 */ 037class PercentileFunDef extends AbstractAggregateFunDef { 038 static final ReflectiveMultiResolver Resolver = 039 new ReflectiveMultiResolver( 040 "Percentile", 041 "Percentile(<Set>, <Numeric Expression>, <Percent>)", 042 "Returns the value of the tuple that is at a given percentile of a set.", 043 new String[] {"fnxnn"}, 044 PercentileFunDef.class); 045 046 public PercentileFunDef(FunDef dummyFunDef) { 047 super(dummyFunDef); 048 } 049 050 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 051 final ListCalc listCalc = 052 compiler.compileList(call.getArg(0)); 053 final Calc calc = 054 compiler.compileScalar(call.getArg(1), true); 055 final DoubleCalc percentCalc = 056 compiler.compileDouble(call.getArg(2)); 057 return new AbstractDoubleCalc( 058 call, new Calc[] {listCalc, calc, percentCalc}) 059 { 060 public double evaluateDouble(Evaluator evaluator) { 061 TupleList list = evaluateCurrentList(listCalc, evaluator); 062 double percent = percentCalc.evaluateDouble(evaluator) * 0.01; 063 final int savepoint = evaluator.savepoint(); 064 try { 065 evaluator.setNonEmpty(false); 066 final double percentile = 067 percentile(evaluator, list, calc, percent); 068 return percentile; 069 } finally { 070 evaluator.restore(savepoint); 071 } 072 } 073 074 public boolean dependsOn(Hierarchy hierarchy) { 075 return anyDependsButFirst(getCalcs(), hierarchy); 076 } 077 }; 078 } 079} 080 081// End PercentileFunDef.java