BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to adapt a piece of JavaScript code for my purposes and it contains the following function:

function _DateInterval( vv ) { var bb = 140*24*60*60*1000; //140 days if( vv >= bb ) { //140 days < 5 months bb = 8766*60*60*1000;//1 year if( vv < bb ) return( bb/12 ); // 1 year //1 mo +nth if( vv < bb *2 ) return( bb/6 ); // 2 years //2 mo +nth if( vv < bb *5/2 ) return( bb/4 ); // 2.5 years //3 mo +nth if( vv < bb *5 ) return( bb/2 ); // 5 years //6 mo +nth if( vv < bb *10 ) return( bb ); // 10 years //1 ye +ar if( vv < bb *20 ) return( bb*2 ); // 20 years //2 ye +ars if( vv < bb *50 ) return( bb*5 ); // 50 years //5 ye +ars if( vv < bb *100 ) return( bb*10 ); // 100 years //10 y +ears if( vv < bb *200 ) return( bb*20 ); // 200 years //20 y +ears if( vv < bb *500 ) return( bb*50 ); // 500 years //50 y +ears return( bb*100 ); //100 years } bb /= 2; //70 days if( vv >= bb ) return( bb/5 ); //14 days bb /= 2; //35 days if( vv >= bb ) return( bb/5 ); //7 days bb /= 7; bb *= 4; //20 days if( vv >= bb ) return( bb/5 ); //4 days bb /= 2; //10 days if( vv >= bb ) return( bb/5 ); //2 days bb /= 2; //5 days if( vv >= bb ) return( bb/5 ); //1 day bb /= 2; //2.5 days if( vv >= bb ) return( bb/5 ); //12 hours bb *= 3; bb /= 5; //1.5 day if( vv >= bb ) return( bb/6 ); //6 hours bb /= 2; //18 hours if( vv >= bb ) return( bb/6 ); //3 hours bb *= 2; bb /= 3; //12 hours if( vv >= bb ) return( bb/6 ); //2 hours bb /= 2; //6 hours if( vv >= bb ) return( bb/6 ); //1 hour bb /= 2; //3 hours if( vv >= bb ) return( bb/6 ); //30 mins bb /= 2; //1.5 hours if( vv >= bb ) return( bb/6 ); //15 mins bb *= 2; bb /= 3; //1 hour if( vv >= bb ) return( bb/6 ); //10 mins bb /= 3; //20 mins if( vv >= bb ) return( bb/4 ); //5 mins bb /= 2; //10 mins if( vv >= bb ) return( bb/5 ); //2 mins bb /= 2; //5 mins if( vv >= bb ) return( bb/5 ); //1 min bb *= 3; bb /= 2; //3 mins if( vv >= bb ) return( bb/6 ); //30 secs bb /= 2; //1.5 mins if( vv >= bb ) return( bb/6 ); //15 secs bb *= 2; bb /= 3; //1 min if( vv >= bb ) return( bb/6 ); //10 secs bb /= 3; //20 secs if( vv >= bb ) return( bb/4 ); //5 secs bb /= 2; //10 secs if( vv >= bb ) return( bb/5 ); //2 secs return( bb/10 ); //1 sec }

Since the orignal JS version aparently raised hackles, here's my first attempt at a Perl version along with some code to exercise it:

#! perl -slw use strict; sub func { my $vv = shift; my $bb = 140*24*60*60*1000; ##140 days if( $vv >= $bb ) { ##140 days < 5 months $bb = 8766*60*60*1000;##1 year if( $vv < $bb ) { return( $bb/12 ); } ## 1 year + ##1 month if( $vv < $bb *2 ) { return( $bb/6 ); } ## 2 years + ##2 month if( $vv < $bb *5/2 ) { return( $bb/4 ); } ## 2.5 years + ##3 month if( $vv < $bb *5 ) { return( $bb/2 ); } ## 5 years + ##6 month if( $vv < $bb *10 ) { return( $bb ); } ## 10 years + ##1 year if( $vv < $bb *20 ) { return( $bb*2 ); } ## 20 years + ##2 years if( $vv < $bb *50 ) { return( $bb*5 ); } ## 50 years + ##5 years if( $vv < $bb *100 ) { return( $bb*10 ); } ## 100 years + ##10 years if( $vv < $bb *200 ) { return( $bb*20 ); } ## 200 years + ##20 years if( $vv < $bb *500 ) { return( $bb*50 ); } ## 500 years + ##50 years return( $bb*100 ); ##100 years } $bb /= 2; ##70 days if( $vv >= $bb ) { return( $bb/5 ); } ##14 days $bb /= 2; ##35 days if( $vv >= $bb ) { return( $bb/5 ); } ##7 days $bb /= 7; $bb *= 4; ##20 days if( $vv >= $bb ) { return( $bb/5 ); } ##4 days $bb /= 2; ##10 days if( $vv >= $bb ) { return( $bb/5 ); } ##2 days $bb /= 2; ##5 days if( $vv >= $bb ) { return( $bb/5 ); } ##1 day $bb /= 2; ##2.5 days if( $vv >= $bb ) { return( $bb/5 ); } ##12 hours $bb *= 3; $bb /= 5; ##1.5 day if( $vv >= $bb ) { return( $bb/6 ); } ##6 hours $bb /= 2; ##18 hours if( $vv >= $bb ) { return( $bb/6 ); } ##3 hours $bb *= 2; $bb /= 3; ##12 hours if( $vv >= $bb ) { return( $bb/6 ); } ##2 hours $bb /= 2; ##6 hours if( $vv >= $bb ) { return( $bb/6 ); } ##1 hour $bb /= 2; ##3 hours if( $vv >= $bb ) { return( $bb/6 ); } ##30 mins $bb /= 2; ##1.5 hours if( $vv >= $bb ) { return( $bb/6 ); } ##15 mins $bb *= 2; $bb /= 3; ##1 hour if( $vv >= $bb ) { return( $bb/6 ); } ##10 mins $bb /= 3; ##20 mins if( $vv >= $bb ) { return( $bb/4 ); } ##5 mins $bb /= 2; ##10 mins if( $vv >= $bb ) { return( $bb/5 ); } ##2 mins $bb /= 2; ##5 mins if( $vv >= $bb ) { return( $bb/5 ); } ##1 min $bb *= 3; $bb /= 2; ##3 mins if( $vv >= $bb ) { return( $bb/6 ); } ##30 secs $bb /= 2; ##1.5 mins if( $vv >= $bb ) { return( $bb/6 ); } ##15 secs $bb *= 2; $bb /= 3; ##1 min if( $vv >= $bb ) { return( $bb/6 ); } ##10 secs $bb /= 3; ##20 secs if( $vv >= $bb ) { return( $bb/4 ); } ##5 secs $bb /= 2; ##10 secs if( $vv >= $bb ) { return( $bb/5 ); } ##2 secs return( $bb/10 ); ##1 sec } printf "%f -> %f\n", $_, func( $_ ) for map 10**$_, -2 .. +14; __END__ [18:49:55.78] E:\Chart>junk 0.010000 -> 2500.000000 0.100000 -> 2500.000000 1.000000 -> 2500.000000 10.000000 -> 2500.000000 100.000000 -> 2500.000000 1000.000000 -> 2500.000000 10000.000000 -> 2500.000000 100000.000000 -> 12500.000000 1000000.000000 -> 120000.000000 10000000.000000 -> 900000.000000 100000000.000000 -> 10800000.000000 1000000000.000000 -> 172800000.000000 10000000000.000000 -> 1209600000.000000 100000000000.000000 -> 15778800000.000000 1000000000000.000000 -> 157788000000.000000 10000000000000.000000 -> 1577880000000.000000 100000000000000.000000 -> 3155760000000.000000

It is obviously ripe for refactoring, but can anyone

  1. work out what (beyond:"mapping one number to another") it is doing?
  2. perceive the mapping sufficiently to simplify (preferably:calculate) the mapping?

I'm not sure that you can take much guidance from the comments; as in context, the function does not seem to be being used for anything date or time related?


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
li

Replies are listed 'Best First'.
Re: [OT] Mysterious function. (Updated)
by RichardK (Parson) on Apr 23, 2015 at 18:13 UTC

    My _guess_ is that it's working out where to put the graduations when drawing a graph.

    i.e. when the graphed interval is 1 year put tick marks every 1 month, 2 years - ticks every 2 months, .. 500 years - ticks every 50 years. There is some obvious repetition -- you could scale some of the results, as the answer for (100 - 1000) is ten times as big as that for (10 - 100). HTH

      Thank you! Now you've pointed it out, it makes a lot of sense in isolation.

      In the actual example it appears to be called for all three axis, only one of which is date related.

      But then there is some conditional code that is rather opaque; so it might be that it is only used by the months axis.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: [OT] Mysterious function.
by jeffa (Bishop) on Apr 23, 2015 at 17:51 UTC

    I used node.js to produce some interesting edge cases. The values on the left were plugged into this confusing function and the values on the right are the results of the function.

    0 = 2500 24999 = 2500 25000 = 5000 49999 = 5000 50000 = 12500 149999 = 12500 150000 = 25000 224999 = 25000 225000 = 37500 299999 = 37500 300000 = 60000 599999 = 60000 600000 = 120000 1199999 = 120000 1200000 = 300000 3599999 = 300000 3600000 = 600000 5399999 = 600000 5400000 = 900000 10799999 = 900000 10800000 = 1800000 21599999 = 1800000 21600000 = 3600000

    Perhaps you can make some heads or tails out of the pattern, but i cannot. I sincerely hope this helps, however.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      Thanks. You inspired a way to work out the transition points:

      #! perl -slw use strict; sub func { my $vv = shift; my $bb = 140*24*60*60*1000; ##140 days if( $vv >= $bb ) { ##140 days < 5 months $bb = 8766*60*60*1000;##1 year if( $vv < $bb ) { return( $bb/12 ); } ## 1 year + ##1 month if( $vv < $bb *2 ) { return( $bb/6 ); } ## 2 years + ##2 month if( $vv < $bb *5/2 ) { return( $bb/4 ); } ## 2.5 years + ##3 month if( $vv < $bb *5 ) { return( $bb/2 ); } ## 5 years + ##6 month if( $vv < $bb *10 ) { return( $bb ); } ## 10 years + ##1 year if( $vv < $bb *20 ) { return( $bb*2 ); } ## 20 years + ##2 years if( $vv < $bb *50 ) { return( $bb*5 ); } ## 50 years + ##5 years if( $vv < $bb *100 ) { return( $bb*10 ); } ## 100 years + ##10 years if( $vv < $bb *200 ) { return( $bb*20 ); } ## 200 years + ##20 years if( $vv < $bb *500 ) { return( $bb*50 ); } ## 500 years + ##50 years return( $bb*100 ); ##100 years } $bb /= 2; ##70 days if( $vv >= $bb ) { return( $bb/5 ); } ##14 days $bb /= 2; ##35 days if( $vv >= $bb ) { return( $bb/5 ); } ##7 days $bb /= 7; $bb *= 4; ##20 days if( $vv >= $bb ) { return( $bb/5 ); } ##4 days $bb /= 2; ##10 days if( $vv >= $bb ) { return( $bb/5 ); } ##2 days $bb /= 2; ##5 days if( $vv >= $bb ) { return( $bb/5 ); } ##1 day $bb /= 2; ##2.5 days if( $vv >= $bb ) { return( $bb/5 ); } ##12 hours $bb *= 3; $bb /= 5; ##1.5 day if( $vv >= $bb ) { return( $bb/6 ); } ##6 hours $bb /= 2; ##18 hours if( $vv >= $bb ) { return( $bb/6 ); } ##3 hours $bb *= 2; $bb /= 3; ##12 hours if( $vv >= $bb ) { return( $bb/6 ); } ##2 hours $bb /= 2; ##6 hours if( $vv >= $bb ) { return( $bb/6 ); } ##1 hour $bb /= 2; ##3 hours if( $vv >= $bb ) { return( $bb/6 ); } ##30 mins $bb /= 2; ##1.5 hours if( $vv >= $bb ) { return( $bb/6 ); } ##15 mins $bb *= 2; $bb /= 3; ##1 hour if( $vv >= $bb ) { return( $bb/6 ); } ##10 mins $bb /= 3; ##20 mins if( $vv >= $bb ) { return( $bb/4 ); } ##5 mins $bb /= 2; ##10 mins if( $vv >= $bb ) { return( $bb/5 ); } ##2 mins $bb /= 2; ##5 mins if( $vv >= $bb ) { return( $bb/5 ); } ##1 min $bb *= 3; $bb /= 2; ##3 mins if( $vv >= $bb ) { return( $bb/6 ); } ##30 secs $bb /= 2; ##1.5 mins if( $vv >= $bb ) { return( $bb/6 ); } ##15 secs $bb *= 2; $bb /= 3; ##1 min if( $vv >= $bb ) { return( $bb/6 ); } ##10 secs $bb /= 3; ##20 secs if( $vv >= $bb ) { return( $bb/4 ); } ##5 secs $bb /= 2; ##10 secs if( $vv >= $bb ) { return( $bb/5 ); } ##2 secs return( $bb/10 ); ##1 sec } my $last = 0; my $step = 2500; for( my $i = 1; $i < 100*365.25*24*60*60*1000; $i += $step ) { my $new = func( $i ); if( $new > $last ) { printf "%20u -> %20u\n", $i, $new; $step = ( $new - $last ) / 10; $last = $new; } } __END__ [19:49:46.77] E:\Chart>junk 1 -> 2500 25001 -> 5000 50001 -> 12500 150501 -> 25000 225501 -> 37500 300501 -> 60000 602001 -> 120000 1202001 -> 300000 3614001 -> 600000 5414001 -> 900000 10814001 -> 1800000 21614001 -> 3600000 43214001 -> 7200000 64814001 -> 10800000 129614001 -> 21600000 216014001 -> 43200000 432014001 -> 86400000 864014001 -> 172800000 1728014001 -> 345600000 3024014001 -> 604800000 6056654001 -> 1209600000 12104654001 -> 2629800000 31561394001 -> 5259600000 63118994001 -> 7889400000 78897794001 -> 15778800000 157791794001 -> 31557600000 315579794001 -> 63115200000 631155794001 -> 157788000000 1577883794001 -> 315576000000
      I used node.js to produce some interesting edge cases.

      'scuse my ignorance, but does node.js allow you to run JS at the command line?


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        Excellent! :) Yes, node.js allows you to run JS at the command line. It is quite a handy tool to have at your disposal:

        var last = 0 var step = 2500 for (var i = 1; i <= 100*365.25*24*60*60*1000; i += step) { j = _DateInterval( i ) if ( j > last ) { console.log( i + ' -> ' + j ); step = ( j - last ) / 10; last = j; } } function _DateInterval( vv ) { .... }

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)