/* Get an idea of data-distribution. Computes distribution index, and some more well known data-summary indexes (max/min, average, etc). Copyright (C) 2006 J.H.Boersema This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation (Version 2, or any later at your option). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define NADDI_VERSION "1.3" /* change this */ #include /* gcc -lm naddi.c -o naddi */ #include #include #include #include int main ( int argc , char * * argv ) { FILE * tempfile ; /* memory file */ FILE * input ; /* input stream, changed to tempfile later */ FILE * output ; /* stdout */ long double data_in_content = 0 ; /* value */ long double data_in_freq = 0 ; /* frequency */ long double zero_adjust = 0 ; /* adjust values upward if negative * value found. Also used for --offset argument. */ long double total_content = 0 ; /* sum of values */ long double total_elements = 0 ; /* total frequency */ long double average_content = 0 ; /* average of element values */ long double index = 0 ; /* element-distribution-index */ long double total_index = 0; /* sum of element-distribution-indeces */ const long double index_constant = .5 ; /* the constant in the index */ /* Changing this .5 constant did not work well: * impossible indexes, especially near the extremes, but sometimes * errors close to .5. * Multiplying input does not change index. */ long int count_pairs = 0 ; /* count input pairs, for error-report */ int arg_verbose = 0 ; /* verbose level */ int arg_fraction = 0 ; /* print distr.index as fraction */ int arg_average = 0 ; /* print basic average */ int arg_extreme = 0 ; /* print max/middle/min */ int arg_share = 0 ; /* print share up to divide */ int arg_precision = 0 ; /* flag to determine if user re-set precion */ int arg_divide_rule = 0 ; /* fraction used to determine 'middle' */ int arg_index_all = 0 ; /* print max/middle/min naddi */ int arg_divide_100 = 0 ; /* remember if arg_divide_rule was given as % */ int arg_fizz = 0 ; /* print --share in popularized format */ int arg_adjust = 0 ; /* adjust all values up/down */ int arg_gotfile = 0 ; /* flow control bool, arg-processing: files */ int precision = 10 ; /* default precision */ int precision2 = 6 ; int precision3 = 0 ; int precision4 = 1 ; char * option_vector ; /* current argv [ N ] being processed */ int option_count ; /* current argv [ option_count ] being processed */ long double maximum = 0 ; /* value maximum */ long double minimum = 0 ; /* value minimum */ long double median_element = 0 ; /* the `nth' element to search for (computed) */ long double median_countup = 0 ; /* count the elements until `nth' */ long double median = 0 ; /* the value of the median element */ int median_gotit = 0 ; /* flow boolian */ long double median_uptosum = 0 ; /* compute value contained up to median */ int median_fracture = 0 ; /* remember if there was no true value on divide */ long double median_divide_rule = .5 ; /* This is used to determine what * factor the 'middle' element is from the number of elements. If it is * .5, the middle * results, if it is .1, the "top 10%" result. */ int loop_init = 0 ; /* flow control first input loop */ /* Name input/output streams */ input = stdin ; output = stdout ; /* proces aruments */ for ( option_count = 1 ; option_count < argc ; option_count ++ ) { option_vector = argv [ option_count ] ; /* non-option argument ? */ if ( 0 != strncmp ( "-" , option_vector , 1 ) ) { if ( 0 == arg_gotfile ) { if ( 0 == ( input = fopen ( option_vector , "r" ) ) ) { fprintf ( stderr , "Error: could not open file \"%s\", aborting.\n" , option_vector ) ; return 1 ; } } else { if ( 0 == ( output = fopen ( option_vector , "a" ) ) ) { fprintf ( stderr , "Error: could not open file \"%s\", aborting.\n" , option_vector ) ; return 1 ; } } arg_gotfile = 1 ; continue ; } if ( 0 == strcmp ( "--formula" , option_vector ) ) { printf ( " Average-Data / Element-Data\n" ) ; printf ( " naddi = 2 * Sum { .5 ^ } / Total-Elements\n" ) ; printf ( "\n" ) ; printf ( " Average-Data = Total-Data / Total-elements\n" ) ; printf ( " Total-Data = The total of all data corresponding to all elements.\n" ) ; printf ( " Element-Data = The data corresponding to element N = 1, 2, 3, ..., N+1.\n" ) ; printf ( " Total-elements = The total number of elements.\n" ) ; printf ( " Element-Index *) = 0.5 ^ ( Average-Data / Element-Data ) \n" ) ; printf ( " Sum { ... } = The Element-indexes for each element, added together.\n" ) ; printf ( " Average-Index = Sum { Element-Indexes } / Total-elements\n" ) ; printf ( " Normalized-Average-Data-Distribution-Index = 100%% * 2 * Average-Index\n" ) ; printf ( " ( ^ means `power' )\n" ) ; printf ( "\n" ) ; printf ( "*) Printed in verbose mode.\n" ) ; return 0 ; } if ( 0 == strcmp ( "--help" , option_vector ) || 0 == strcmp ( "-h" , option_vector ) ) { printf ( "Usage: naddi [OPTIONS ...] [INFILE [OUTFILE]]\n" ) ; printf ( "Compute distribution index.\n\n" ) ; printf ( " -a --average sum, frequency and average of element values\n" ) ; printf ( " -dF[%%] --divide=F[%%] -e, -E and -s \'middle\' Fraction (default 50%%)\n" ) ; printf ( " -e --extreme minimum, \'middle\', maximum element values\n" ) ; printf ( " -E --extreme-index minimum, \'middle\', maximum element index\n" ) ; printf ( " -f --fraction distribution as fraction\n" ) ; printf ( " --formula print the distribution formula\n" ) ; printf ( " --fizz [--fizz] print --share verbosely\n" ) ; printf ( " -h --help this\n" ) ; printf ( " -oV --offset=V offset V for values for index computation\n" ) ; printf ( " -pN --precision=N precision N for calculations and output\n" ) ; printf ( " -s --share fraction of value until \'middle\'\n" ) ; printf ( " -v[N] --verbose[=N] verbosity N (max 4)\n" ) ; printf ( " --version print program version\n" ) ; printf ( "\nReads (sorted) pairs of numbers separated by whitespace.\nFirst number: a value, second number: its frequency.\n" ) ; return 0 ; } if ( 0 == strcmp ( "--version" , option_vector ) ) { printf ( "naddi " NADDI_VERSION "\n" ) ; return 0 ; } if ( 0 == strncmp ( "--verbose=" , option_vector , 10 ) ) { sscanf ( option_vector , "--verbose=%d" , &arg_verbose ) ; } if ( 0 == strcmp ( "--verbose" , option_vector ) || 0 == strcmp ( "-v" , option_vector ) ) { arg_verbose ++ ; } if ( 0 == strncmp ( "-v" , option_vector , 2 ) ) { sscanf ( option_vector , "-v%d" , &arg_verbose ) ; } if ( 0 == strcmp ( "--fraction" , option_vector ) || 0 == strcmp ( "-f" , option_vector ) ) { arg_fraction = 1 ; } if ( 0 == strcmp ( "--extreme-index" , option_vector ) || 0 == strcmp ( "-E" , option_vector ) ) { arg_index_all = 1 ; } if ( 0 == strcmp ( "--average" , option_vector ) || 0 == strcmp ( "-a" , option_vector ) ) { arg_average = 1 ; } if ( 0 == strcmp ( "--extreme" , option_vector ) || 0 == strcmp ( "-e" , option_vector ) ) { arg_extreme = 1 ; } if ( 0 == strcmp ( "--share" , option_vector ) || 0 == strcmp ( "-s" , option_vector ) ) { arg_share = 1 ; } if ( 0 == strncmp ( "--offset=" , option_vector , 9 ) ) { sscanf ( option_vector , "--offset=%Lf" , &zero_adjust ) ; arg_adjust = 1 ; } if ( 0 == strncmp ( "-o" , option_vector , 2 ) ) { sscanf ( option_vector , "-o%Lf" , &zero_adjust ) ; arg_adjust = 1 ; } if ( 0 == strncmp ( "--precision=" , option_vector , 12 ) ) { sscanf ( option_vector , "--precision=%d" , &precision ) ; arg_precision = 1 ; /* user specified */ } if ( 0 == strncmp ( "-p" , option_vector , 2 ) ) { sscanf ( option_vector , "-p%d" , &precision ) ; arg_precision = 1 ; /* user specified */ } if ( 0 == strncmp ( "--divide=" , option_vector , 9 ) ) { sscanf ( option_vector , "--divide=%Lf" , &median_divide_rule ) ; arg_divide_rule = 1 ; /* user specified */ if ( '%' == option_vector [ strlen ( option_vector ) - 1 ] ) { median_divide_rule /= 100 ; arg_divide_100 = 1 ; } } if ( 0 == strncmp ( "-d" , option_vector , 2 ) ) { sscanf ( option_vector , "-d%Lf" , &median_divide_rule ) ; arg_divide_rule = 1 ; /* user specified */ if ( '%' == option_vector [ strlen ( option_vector ) - 1 ] ) { median_divide_rule /= 100 ; arg_divide_100 = 1 ; } } if ( 0 == strcmp ( "--fizz" , option_vector ) ) { arg_share = 1 ; /* --fizz has no meaning without it */ arg_fizz ++ ; } } /* Open tempfile, a memory-file because data is read twice. */ if ( 0 == ( tempfile = tmpfile ( ) ) ) { fprintf ( stderr , "Could not get temporary file pointer from \"tmpfile ( ) ;\", aborting\n" ) ; return 3 ; } /* Process data: get totals first. */ count_pairs = 0 ; loop_init = 0 ; while ( EOF != fscanf ( input , " %Lf" , &data_in_content ) ) { count_pairs ++ ; /* have to have max/min at the end of this loop */ if ( 0 == loop_init ) { loop_init = 1 ; minimum = maximum = data_in_content ; } /* find maximum/minimum element values */ if ( maximum < data_in_content ) { maximum = data_in_content ; } if ( minimum > data_in_content ) { minimum = data_in_content ; } /* Remember, for re-reading with totals-data */ fprintf ( tempfile , "%.*Lg" , precision , data_in_content ) ; if ( EOF == fscanf ( input , " %Lf" , &data_in_freq ) ) { fprintf ( stderr , "Error occurred in data-pair %ld\n" , count_pairs ) ; fprintf ( stderr , "Missing `amount of occurrences' data element, aborting\n" ) ; return 1 ; } /* Remember, for re-reading with totals-data */ fprintf ( tempfile , " %Lf\n" , data_in_freq ) ; if ( 0 > ( total_elements += data_in_freq ) ) { fprintf ( stderr , "Error: number of elements overflowed, aborting\n" ) ; return 2 ; } total_content += data_in_content * data_in_freq ; } average_content = total_content / total_elements ; median_element = median_divide_rule * total_elements ; /* Warning: median expects sorted input if it is to mean much*/ rewind ( tempfile ) ; /* ... reread input stream, with totals in hand */ input = tempfile ; /* copy/paste */ /* The naddi does not handle negative numbers at all (weird * results). Should someone feed it negative values, all * values are made higher so the minimum is at least 0. This * is only used when computing the naddi, average, max/min * etc are not affected. */ if ( 0 > minimum ) { zero_adjust += fabsl ( minimum ) ; } else if ( 1 == arg_adjust && 0 == zero_adjust ) { /* User gave --offset=0, to signal that the minimum * value should be "0", adjust downward if necessary. * Apparently 0 <= minimum, so should subtract. */ zero_adjust = -1 * minimum ; } /* verboseness formatting */ if ( 3 == arg_verbose ) { fprintf ( output , "value" ) ; if ( 0 != zero_adjust ) { fprintf ( output , " offset ( %Lf )" , zero_adjust ) ; } fprintf ( output , " frequency element-distribution ( 0%% - 100%% )\n" ) ; } else if ( 3 < arg_verbose ) { fprintf ( output , "value" ) ; if ( 0 != zero_adjust ) { fprintf ( output , " offset ( %Lf )" , zero_adjust ) ; } fprintf ( output , " frequency element-distribution ( 0 - 1 )\n" ) ; } /* Process data: compute index total. */ count_pairs = 0 ; while ( EOF != fscanf ( input , " %Lf" , &data_in_content ) ) { count_pairs++ ; if ( EOF == fscanf ( input , " %Lf" , &data_in_freq ) ) { fprintf ( stderr , "Error occurred in data-pair %ld\n" , count_pairs ) ; fprintf ( stderr , "Missing `amount of occurrences' data element, aborting\n" ) ; return 1 ; } /* hit or overshot median target */ if ( 1 != median_gotit && median_countup + data_in_freq >= median_element ) { median = data_in_content ; /* keep it simple */ /* Tried to do a proportional "take average of adjacent values" thing, * but it was too hairy for me. The necessity is also doubtful. * This way, users get more information if they want it, and it is FAR * simpler to program. */ median_gotit = 1 ; /* lock out */ median_uptosum += data_in_content * ( median_element - median_countup ) ; if ( median_countup + data_in_freq == median_element ) { median_fracture = 1 ; } } if ( 1 != median_gotit ) { median_countup += data_in_freq ; /* compute input-stream total until median encountered */ median_uptosum += data_in_content * data_in_freq ; } /* fail quickly */ if ( 0 > data_in_content + zero_adjust ) { fprintf ( stderr , "Error: negative value %Lg in data-pair %ld, offset: %Lg\n" , data_in_content + zero_adjust , count_pairs , zero_adjust ) ; return 1 ; } /* element-index */ if ( 0 == average_content + zero_adjust ) { /* If the average is zero, then, since no values can * be below 0, the total must also be 0 (barring * precision problems). If the total is 0 while * adjusted, all values must be 0. Hence: completely * equal distribution. */ index = .5 ; /* rare exception */ /* The minimum/middle/max values give nan, * to hint at the problem. Useless anyway for * 100% equality. */ } else { index = powl ( index_constant , ( average_content + zero_adjust ) / ( data_in_content + zero_adjust ) ) ; } /* grand total of element-indexes */ total_index += index * data_in_freq ; /* verbosity, printing element-indexes */ if ( 0 != arg_verbose ) { /* print percentage */ if ( 3 == arg_verbose ) { if ( 0 == arg_precision ) { fprintf ( output , "%.6Lg" , data_in_content ) ; if ( 0 != zero_adjust ) { fprintf ( output , " %.*Lg" , precision , data_in_content + zero_adjust ) ; } fprintf ( output , " %.6Lg %.0Lf%%\n" , data_in_freq , index * 100 ) ; } else { fprintf ( output , "%.*Lg" , precision , data_in_content ) ; if ( 0 != zero_adjust ) { fprintf ( output , " %.*Lg" , precision , data_in_content + zero_adjust ) ; } fprintf ( output , " %.*Lg %.*Lg%%\n" , precision , data_in_freq , precision , index * 100 ) ; } } else if ( 3 < arg_verbose ) { /* print fraction (whatever) */ fprintf ( output , "%.*Lg" , precision , data_in_content ) ; if ( 0 != zero_adjust ) { fprintf ( output , " %.*Lg" , precision , data_in_content + zero_adjust ) ; } fprintf ( output , " %.*Lg %.*Lg\n" , precision , data_in_freq , precision , index ) ; } } } /* should have found everything ...*/ /* Test for weirdness by checking impossible result */ if ( ! ( 0 <= ( total_index / total_elements ) / index_constant || 1 >= ( total_index / total_elements ) / index_constant ) ) { fprintf ( stderr , "Error, impossible distribution: beyond 0%%-100%% (%Lf%%), aborting.\n" , 100 * ( total_index / total_elements ) / index_constant ) ; return 2 ; } /* print results */ /* This is probably a little overweight, but why delete it now that * it seems to work. Does give nice default precision values IMHO. */ /* user did not specify precision */ if ( 1 == arg_precision ) { precision2 = precision ; precision3 = precision ; precision4 = precision ; } /* print results */ if ( 0 < arg_verbose ) { if ( 2 < arg_verbose ) { fprintf ( output , "\n" ) ; } if ( 1 < arg_verbose ) { fprintf ( output , "%.*Lg sum ( value )\n" , precision2 , total_content ) ; fprintf ( output , "%.*Lg elements ( frequency )\n" , precision2 , total_elements ) ; fprintf ( output , "%.*Lg average ( value )\n" , precision2 , average_content ) ; } fprintf ( output , "%.*Lg factor ( maximum ( value ) / minimum ( value ) )\n" , precision2 , maximum / minimum ) ; if ( 1 < arg_verbose ) { fprintf ( output , "\n" ) ; fprintf ( output , "%.*Lg minimum ( value )\n" , precision2 , minimum ) ; fprintf ( output , "%.*Lg" , precision2 , median ) ; /* no \n */ if ( 0 == arg_divide_rule ) { fprintf ( output , " middle ( value )" ) ; } else { fprintf ( output , " element-%.*Lf%%-input ( value )" , precision3 , 100 * median_divide_rule ) ; } if ( 0 == median_fracture ) { fprintf ( output , "\n" ) ; } else { fprintf ( output , " \n" ) ; } fprintf ( output , "%.*Lg maximum ( value )\n" , precision2 , maximum ) ; if ( 2 < arg_verbose ) { fprintf ( output , "%.*Lg share ( value up to" , precision2 , median_uptosum ) ; if ( 0 == arg_divide_rule ) { fprintf ( output , " middle )\n" ) ; } else { fprintf ( output , " element-%.*Lf%%-input )\n" , precision2 , 100 * median_divide_rule ) ; } } fprintf ( output , "%.*Lf%% share ( value%% up to" , precision3 , 100 * median_uptosum / total_content ) ; if ( 0 == arg_divide_rule ) { fprintf ( output , " middle )\n" ) ; } else { fprintf ( output , " element-%.*Lf%%-input )\n" , precision3 , 100 * median_divide_rule ) ; } fprintf ( output , "\n" ) ; } if ( 1 < arg_verbose ) { fprintf ( output , "%.*Lf%% minimum ( element index )\n" , precision3 , 100 * powl ( index_constant , ( average_content + zero_adjust ) / ( minimum + zero_adjust ) ) ) ; fprintf ( output , "%.*Lf%%" , precision3 , 100 * powl ( index_constant , ( average_content + zero_adjust ) / ( median + zero_adjust ) ) ) ; if ( 0 == arg_divide_rule ) { fprintf ( output , " middle ( element index )\n" ) ; } else { fprintf ( output , " element-%.*Lf%%-input ( element index )\n" , precision3 , 100 * median_divide_rule ) ; } fprintf ( output , "%.*Lf%% maximum ( element index )\n" , precision3 , 100 * powl ( index_constant , ( average_content + zero_adjust ) / ( maximum + zero_adjust ) ) ) ; } fprintf ( output , "%.*Lf%% distribution ( naddi )\n" , precision4 , 100 * ( total_index / total_elements ) / index_constant ) ; } /* print results from directly asking arguments */ if ( 1 == arg_extreme ) { fprintf ( output , "%.*Lg\n%.*Lg\n%.*Lg\n" , precision , minimum , precision , median , precision , maximum ) ; } if ( 1 == arg_average ) { fprintf ( output , "%.*Lg\n" , precision , total_content ) ; fprintf ( output , "%.*Lg\n" , precision , total_elements ) ; fprintf ( output , "%.*Lg\n" , precision , average_content ) ; } if ( 1 == arg_share ) { if ( 1 == arg_fizz ) { fprintf ( output , "The top %.0Lf%% corresponds to %.0Lf%% of the value.\n" , 100 * median_divide_rule , 100 * median_uptosum / total_content ) ; } else if ( 1 < arg_fizz ) { fprintf ( output , "The bottom %.0Lf%% corresponds to %.0Lf%% of the value.\n" , 100 * median_divide_rule , 100 * median_uptosum / total_content ) ; } else { if ( 0 == arg_divide_100 ) { fprintf ( output , "%.*Lf\n" , precision , median_uptosum / total_content ) ; /* fraction */ } else { if ( 0 == arg_precision ) { /* percentage */ fprintf ( output , "%.1Lf%%\n" , 100 * median_uptosum / total_content ) ; } else { fprintf ( output , "%.*Lf%%\n" , precision , 100 * median_uptosum / total_content ) ; } } } } if ( 1 == arg_index_all ) { fprintf ( output , "%.*Lf\n" , precision , powl ( index_constant , ( average_content + zero_adjust ) / ( minimum + zero_adjust ) ) ) ; fprintf ( output , "%.*Lf\n" , precision , powl ( index_constant , ( average_content + zero_adjust ) / ( median + zero_adjust ) ) ) ; fprintf ( output , "%.*Lf\n" , precision , powl ( index_constant , ( average_content + zero_adjust ) / ( maximum + zero_adjust ) ) ) ; } if ( 1 == arg_fraction ) { fprintf ( output , "%.*Lf\n" , precision , 2 * ( total_index / total_elements ) ) ; } /* default, if nothing is requested and verbosity is zero: */ if ( 0 == arg_verbose && 0 == arg_fraction && 0 == arg_average && 0 == arg_extreme && 0 == arg_share && 0 == arg_index_all ) { /* follow precision if one is set */ if ( 0 == arg_precision ) { fprintf ( output , "%.1Lf%%\n" , 100 * ( total_index / total_elements ) / index_constant ) ; } else { fprintf ( output , "%.*Lf%%\n" , precision , 100 * ( total_index / total_elements ) / index_constant ) ; } } if ( 4 < arg_verbose ) { fprintf ( stderr , " no more!\n" ) ; return 1 ; } return 0 ; } /* * This index may already be in use somewhere under another name, I have * no idea. Whatever the case, it works. NADDI = 2 * Sum ( 0.5 ^ ( Average-Data / Element-Data ) ) / Total-Elements * Normalized Average Data Distribution Index, NADDI: * NADDI = 2 * ADDI * ADDI = Average Data Distribution Index * ADDI = Sum ( EDDI ) / Ntotal * EDDI = Element Data Distribution Index * EDDI = 0.5 ^ ( Average-Data / Element-Data ) * Average-Data = Total-Data / Total-elements * Element-Data = The data corresponding to element 1, 2, 3, ..., N+1. * Total-Data = The total of all data corresponding to all elements. * Total-elements = The total number of elements in the selection. * * This index was originally meant for economics, but since it is general * purpose in can be used for any data. This utility has no idea what * kind of data it is processing. * * History * * The "Element distribution index" .5 ^ ( average / element ) part of * the equation, was originally meant to be a measure of the relative * "happiness" that would be awarded to that person, from having its * amount of money. That happiness would then increase proportionally * with more money; I believe the element-distribution-index does this * quite realisticly. Someone who has several times the average, gains * much fewer happiness from the same amount of money, as someone who * has much below the average. Naturally, owning twice as much if * you already own much more then average, does not double your `material * happiness' index, it may only improve a few percent. Give 100 units, * enough to buy a good meal, to someone owning 1e6 units, and someone * owning 0 units: a great difference in additional material happiness * awarded by this value. The index is nothing more then the average * of these indexes, normalized to 100%. * * Since the index says nothing about absolute value, the issue * of how large/small average/median is, is outside its view. Hence, the * actual "material happiness" might drop, even if the index sees an * extreme/optimum (choose your vocabulary) of 100% equality: the grand * total might have dropped. * * It can be treated as a black-box figure, that has only meaning when * comparing selections. Saying off-hand without comparison, that 99% * naddi is "very equal" is probably not correct. If a mirror must * be almost absolutely flat, a 99% naddi for deviations may be "very * unequal". Note that the reference-point matters here, sensitivity is * a `factor' around the average. For all selections 30% naddi is less * equal then 70%, ~0% and 100% are the extremes. * * Comparing to some other indexes (note: author of this is not * objective !): * * Looks at distribution single Simplicity * all data shape matters number * Gini: yes yes yes no * Standard-deviation no yes yes- yes- * median *) no no yes very * factor max/min no no yes very * average *) yes/no no yes very * N% has X% yes/no no no yes * naddi yes no yes yes- * *) Not an indication of distribution. * * The Gini index needs a certain distribution-shape, if its use is to * be defended successfully (right?). That means, that not all selections * can be fitted to the Gini coefficient, meaning that we really do not * have a general-purpose measure for (economic) data-distribution, that * can be applied to all data selections. * * The Gini-coefficient seems to fail at least theoretically, * when distribution doesn't follow an `e' function shape, making it * impossible to reach any other distribution-shape, without losing * the tools to measure this distribution. How useful is a measurement * device, that can only measure a limited extend of the quantity being * measured. * * I hope that this formula will be equally useful for science, as for * planning the future by non-science individuals/groups. Because it is * very easy to compute (you need a hand-calculator that can do ".5 to the * power off ...", though), it can be used "in the field". When the * naddi index is to rise, this is accomplished with the least amount * of value transfer, if this value is transferred to the poorest. * (And vica-versa.) Which is probably in line with demands concerning * wealth distribution. * * Compared to "N% has X%": if `the top 10% is to reduce its share * from 90% to 80% of value, this can equally be accomplished by * transferring value to the top 20%, as to the bottom 20%. * * Users should work out themselves what they believe to be the "perfect" * distribution. For some this may be 0%, others 50%, 100%, etc. */