Re: sub as mathematical function
by LanX (Saint) 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
| [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
| [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 (Abbot) 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 (Chancellor) 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 (Patriarch) 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 9-tile 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 (Patriarch) 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] |