Re: sub as mathematical function
by LanX (Archbishop) on Sep 04, 2019 at 11:35 UTC

Provided
> input: float 0 to 1 inclusive
It's
int(9*$v)
Edit
Corrected off by one
Updated
Corrected correction ;)
Updated
The edge case 1=9/9 needs special treatment. Are you sure 8 is the maximum?
If yes max(8,int(9*$v))
max needs to be imported. (POSIX?)
List::Util#max
Cheers Rolf
_{(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery
FootballPerl is like chess, only without the dice
}
 [reply] [d/l] [select] 

min(int(9*$x),8) is perfect thanks all :)
 [reply] [d/l] 

DB<5> print $_,":",max(min(int(9*$_/18),8),0),"\n" for 2..20
2:0
1:0
0:0
1:0
2:1
3:1
4:2
5:2
6:3
7:3
8:4
9:4
10:5
11:5
12:6
13:6
14:7
15:7
16:8
17:8
18:8
19:8
20:8
Cheers Rolf
_{(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery
FootballPerl is like chess, only without the dice
}
 [reply] [d/l] 



>> min(int(9*$x),8)
When number of intervals vary (not only 9), then this looks more general:
my $intervals = 9; min( int( $intervals * $x ), $intervals  1 )
or:
my $intervals = 9; int( $intervals * $x )  int $x
 [reply] [d/l] [select] 
Re: sub as mathematical function
by holli (Monsignor) on Sep 04, 2019 at 11:38 UTC

sub quant{
# 14 characters, but I am bad at this, I'm sure it can get shorter
int((shift)*8)
}
Update:
Hah. I made the same mistake as LanX above. It works up to 8/9, then it fails.
sub quant{ int((shift)*8) }
for ( 1 .. 9 ) {
print "$_ => ", quant( ($_/9)  0.0001 ), "\n";
}
1 => 0
2 => 1
3 => 2
4 => 3
5 => 4
6 => 5
7 => 6
8 => 7
9 => 7 // BOOM!
What do we learn? Test all cases :)
holli
You can lead your users to water, but alas, you cannot drown them.
 [reply] [d/l] [select] 

It also fails for a lot of numbers between the ones you tested (e.g. 0.112 should return 1 but returns 0, 0.23 should return 2 but returns 1, etc).
The fix is simple: Replace 8 with 9 :)
Of course, that assumes the input is in range [0..1), but that seems a sure thing.
 [reply] 
Re: sub as mathematical function
by talexb (Canon) on Sep 04, 2019 at 13:47 UTC

This is a good example of a bad 'code smell'. If you find yourself doing a copy and paste for more than two lines .. you are probably doing it wrong. Also, a test script would have confirmed that this function had implemented the ideal behaviour.
Alex / talexb / Toronto
Thanks PJ. We owe you so much. Groklaw  RIP  2003 to 2013.
 [reply] 
Re: sub as mathematical function
by Corion (Pope) on Sep 04, 2019 at 11:26 UTC

 [reply] 

sorry I dont get what you're saying :( I tried floor(8*$x), round(8*$x), ceil(8*$x) from the POSIX module but their all different from the sub
 [reply] [d/l] [select] 

sub mod_9 {
my( $x ) = @_;
return $x % 9
}
Update: No, I misread the original function. You seem to input a number with decimals and want to know into which 9tile it falls. int ($x*9)1, as LanX notes below, is the correct answer then.  [reply] [d/l] [select] 
Re: sub as mathematical function
by ikegami (Pope) on Sep 04, 2019 at 16:20 UTC

sub quant {
my $v = shift;
return int($v*9);
}
 [reply] [d/l] [select] 

~$ perl E 'say 4 if 0.8333333333333333 < 5/6'
4
~$ perl E 'say int 6 * 0.8333333333333333'
5
For maybe general case of 100 intervals, playing with Data::Float (and from similar experiment literal number above came from):
~$ perl MData::Float=nextdown E '$n=100; for(1..$n){say if $_1 != i
+nt $n*nextdown $_/$n}'
5
10
17
20
23
34
40
46
67
68
80
81
92
93
 [reply] [d/l] [select] 