In the following Kotlin code example I expected the value of parameter i to be equal to 0, such as is the case for the parameter k. The IDE reports all i, j and k as Int. Is it a bug or do I need to readjust my understanding of Kotlin casting inside expressions? For example, is there a rule to always promote/cast to Double inside expressions involving division, but not multiplication?
fun main() {
//Kotlin 1.3.61
val x = 100 * 1.0/100 //Double
val i = 100 * 1/100 //Int
val j = 1/100 //Int
val k = 100 * j //Int
println(x) //1.0
println(i) //1
println(j) //0
println(k) //0
}
I expected the value of parameter i to be equal to 0
The output is arithmetically right: 100 * 1 / 100 = (100 * 1) / 100 = 100 / 100 = 1 / 1 = 1
, such as is the case for the parameter k.
The value j is 0, so anything multiplied by it will be zero, as in case of k.
is there a rule to always promote/cast to Double inside expressions
involving division, but not multiplication?
If you divide integers, you will get an integer back. If one of the numbers is a Double, the result will be a Double:
val x = 100 * 1.0/100 //Double because 1.0 is a Double
--
There is actually already a discussion on kotlin forum to your problem here:
Mathematically speaking the current behaviour is correct.
This is called integer devision and results in the quotient as an
answer
Related
For educational purposes I want to implement the 1-dimensional Perlin Noise algorithm in Kotlin. I familiarized myself with the algorithm here and here.
I think I understood the basic concept, however my implementation can return values greater than 1. I expect the result of the call perlin(x) to be in the range 0 to 1. I can't figure out where I'm mistaken, so maybe someone can point me in the right direction. For simplicity I use simple linear interpolation instead of smoothstep or other advanced techniques for now.
class PerlinNoiseGenerator(seed: Int, private val boundary: Int = 10) {
private var random = Random(seed)
private val noise = DoubleArray(boundary) {
random.nextDouble()
}
fun perlin(x: Double, persistence: Double = 0.5, numberOfOctaves: Int = 8): Double {
var total = 0.0
for (i in 0 until numberOfOctaves) {
val amplitude = persistence.pow(i) // height of the crests
val frequency = 2.0.pow(i) // number of crests per unit distance
val octave = amplitude * noise(x * frequency)
total += octave
}
return total
}
private fun noise(t: Double): Double {
val x = t.toInt()
val x0 = x % boundary
val x1 = if (x0 == boundary - 1) 0 else x0 + 1
val between = t - x
val y0 = noise[x0]
val y1 = noise[x1]
return lerp(y0, y1, between)
}
private fun lerp(a: Double, b: Double, alpha: Double): Double {
return a + alpha * (b - a)
}
}
For example if you would use these random generated noises
private val noise = doubleArrayOf(0.77, 0.02, 0.63, 0.74, 0.49, 0.22, 0.19, 0.76, 0.16, 0.08)
You would end up with an image like this:
where the green line is the calculated Perlin Noise of 8 octaves with a persistence of 0.5. As you can see the sum of all octaves at x=0 for example is greater than 1. (The blue line being the first octave noise(x) and the orange one being the second octave 0.5 * noise(2x)).
What am I doing wrong?
Thanks in advance.
Note: I'm aware that the Simplex Noise algorithm is the successor of Perlin Noise, however for educational purposes I want to implement Perlin Noise first. I'm also aware that my boundary should be set to something in the magnitude of 256 but for simplicity I just used 10 for now.
I've been digging around and found this article which introduces a value to normalize the results returned by Perlin(x). Essentially the amplitudes are summed up and the total is divided by this value. This seems to make sense since we could have "bad luck" and have a y-value of 1.0 in the first octave, followed by a 0.5 in the next, etc. So dividing by the sum of the amplitudes (1.5 in this case with 2 octaves) seems reasonable to keep the values in the range 0 - 1.
However, I'm unsure if this is the preferred way since none of the other resource uses this technique.
The modified code would look like this:
fun perlin(x: Double, persistence: Double = 0.5, numberOfOctaves: Int = 8): Double {
var total = 0.0
var amplitudeSum = 0.0 //used for normalizing results to 0.0 - 1.0
for (i in 0 until numberOfOctaves) {
val amplitude = persistence.pow(i) // height of the crests
val frequency = 2.0.pow(i) // frequency (number of crests per unit distance) doubles per octave
val octave = amplitude * noise(x * frequency)
total += octave
amplitudeSum += amplitude
}
return total / amplitudeSum
}
I have tested while loop below and don’t understand the result.
var x: Float = 0.0
var counter = 0
while x < 1.41
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) // 1.5
How is it possible to have the result x = 1.5 for the used while condition where x < 14.1 ? How to explain this result?
Update:
and one more. Why the results are different for Double and Float ?
var x: Double = -0.5
var counter = 0
while x < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 16
print (x)//1.1
var x: Float = -0.5
var counter = 0
while x < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0
Update 2
and another one. Why there is no difference for < and <= conditions. Does it mean that usage of <= has no sense for floating point ?
var x: Double = 0.0
var counter = 0
while x < 1.5
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) //1.5
var x: Double = 0.0
var counter = 0
while x <= 1.5
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) //1.5
What else would you expect? The loop is executed 15 times. On the 14th time, x is 1.4 and so you add another 0.1, making it 1.5.
If you expect the loop to terminate at 1.4, you should increment x before checking the while condition, not after that.
If you expect the loop to terminate on 1.41, your increment is wrong and you should do
x += 0.01
instead, making it 141 iterations.
As for the second question, I am aware that Float should not be used for monetary calculations and such due to its lack of precision. However, I trusted Double so far, and the while loop in run 15 actually claims the Double value to be less than 1.0 while it is reported to be 1.0. We have got a precision problem here, as we can see if we substract x from 1.0:
print(1.0-x)
which returns: 1.11022302462516e-16
At the same time, Float seems to be unprecise in the other direction. In the last run, it is a little bigger than 0.9 (0.9 + 5.96046e-08), making it bigger than 10 in the following run.
The reason why Double and Float are wrong in different directions is just a matter of how the values are stored, and the result will be different depending on the number. For example, with 2.0 both actual values are bigger: Double by 4.440892..e-16 and Float by 2.38419e-07. For 3.0 Double is bigger by 1.33226e-15 and Float smaller by 7.1525e-07.
The same problems occur using x.isLess(than: 1.0), but this method is the basis for the < operator as of https://developer.apple.com/reference/swift/floatingpoint/1849403-isless
isLessThanOrEqualTo(1.0), on the other hand, seems to work reliably as expected.
This answer is pretty much a question itself by now, so I'm curious if anyone has an in-depth explanation of this...
Update
The more I think about it, the less of a Swift problem it is. Basically, you have that problem in all floating point calculations, because they are never precise. Both Float and Double are not precise, Double is just twice as accurate. However, this means that comparisons like == are useless with floating point values unless they are both rounded. Therefore, good advice in loops like those of yours with a known precision (in your case one decimal) would be to round to that precision before doing any kind of comparison. For example, this would fix the loop:
var x: Double = -0.5
var counter = 0
while (round(x * 1000) / 1000) < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0
var x: Float = -0.5
var counter = 0
while (round(x * 1000) / 1000) < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0
With (float)arc4random() how can I generate a float random number included in [0, 1[ i.e. in the interval 0-1, with 0 included and 1 excluded?
My code is
do {
c = ((float)arc4random() / 0x100000000);
}
while (c == 1.0);
Is there anything better?
It depends how many possible numbers you want in between the two?
But you can use...
float numberOfPossibilities = ...;
float random = (float)arc4random_uniform(numberOfPossibilities) / numberOfPossibilities;
To exclude 1 you could do...
float random = (float)arc4random_uniform(numberOfPossibilities - 1) / numberOfPossibilities;
// Get a value greater than the greatest possible random choice
double one_over_max = UINT32_MAX + 1L;
// Use that as the denominator; this ratio will always be less than 1
double half_open_result = arc4random() / one_over_max;
The resolution -- the number of possible resulting values -- is thus the same as the resolution of the original random function. The gap between the largest result and the top of the interval is the difference between your chosen denominator and the original number of results, over the denominator. In this case, that's 1/4294967296; pretty small.
This is extension for Float Swift 3.1
// MARK: Float Extension
public extension Float {
/// Returns a random floating point number between 0.0 and 1.0, inclusive.
public static var random: Float {
return Float(arc4random()) / 0xFFFFFFFF
}
/// Random float between 0 and n-1.
///
/// - Parameter n: Interval max
/// - Returns: Returns a random float point number between 0 and n max
public static func random(min: Float, max: Float) -> Float {
return Float.random * (max - min) + min
}
}
you can use like:
Float num = (arc4random() % ([[filteredArrayofPerticularword count] FloatValue]));
In that filteredArrayofPerticularword array u can store your number.
I have a float and I am trying to get a random number between 1.5 - 2. I have seen tutorials on the web but all of them are doing the randomization for 0 to a number instead of 1.5 in my case. I know it is possible but I have been scratching my head on how to actually accomplish this. Can anyone help me?
Edit1: I found the following method on the web but I do not want all these decimals places. I only want things like 5.2 or 7.4 etc...
How would I adjust this method to do that?
-(float)randomFloatBetween:(float)num1 andLargerFloat:(float)num2
{
int startVal = num1*10000;
int endVal = num2*10000;
int randomValue = startVal + (arc4random() % (endVal - startVal));
float a = randomValue;
return (a / 10000.0);
}
Edit2: Ok so now my method is like this:
-(float)randomFloatBetween:(float)num1 andLargerFloat:(float)num2
{
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
return val;
}
Will this produce numbers like 1.624566 etc..? Because I only want say 1.5,1.6,1.7,1.8,1.9, and 2.0.
You can just produce a random float from 0 to 0.5 and add 1.5.
EDIT:
You're on the right track. I would use the maximum random value possible as your divisor in order to get the smallest intervals you can between possible values, rather than this arbitrary division by 10,000 thing you have going on. So, define the maximum value of arc4random() as a macro (I just found this online):
#define ARC4RANDOM_MAX 0x100000000
Then to get a value between 1.5 and 2.0:
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
return val;
This will also give you double precision if you want it (just replace float with double.)
EDIT AGAIN:
Yes, of course this will give you values with more than one decimal place. If you want only one, just produce a random integer from 15 to 20 and divide by 10. Or you could just hack off the extra places afterward:
float range = num2 - num1;
float val = ((float)arc4random() / ARC4RANDOM_MAX) * range + num1;
int val1 = val * 10;
float val2= (float)val1 / 10.0f;
return val2;
arc4random is a 32-bit generator. It generates Uint32's. The maximum value of arc4random() is UINT_MAX. (Do not use ULONG_MAX!)
The simplest way to do this is:
// Generates a random float between 0 and 1
inline float randFloat()
{
return (float)arc4random() / UINT_MAX ;
}
// Generates a random float between imin and imax
inline float randFloat( float imin, float imax )
{
return imin + (imax-imin)*randFloat() ;
}
// between low and (high-1)
inline float randInt( int low, int high )
{
return low + arc4random() % (high-low) ; // Do not talk to me
// about "modulo bias" unless you're writing a casino generator
// or if the "range" between high and low is around 1 million.
}
This should work for you:
float mon_rand() {
const u_int32_t r = arc4random();
const double Min = 1.5;
if (0 != r) {
const double rUInt32Max = 1.0 / UINT32_MAX;
const double dr = (double)r;
/* 0...1 */
const double nr = dr * rUInt32Max;
/* 0...0.5 */
const double h = nr * 0.5;
const double result = Min + h;
return (float)result;
}
else {
return (float)Min;
}
}
That was the simplest I could think of, when I had the same "problem" and it worked for me:
// For values from 0.0 to 1.0
float n;
n = (float)((arc4random() % 11) * 0.1);
And in your case, from 1.5 to 2.0:
float n;
n = (float)((arc4random() % 6) * 0.1);
n += 15 * 0.1;
For anybody who wants more digits:
If you just want float, instead of arc4random(3) it would be easier if you use rand48(3):
// Seed (only once)
srand48(arc4random()); // or time(NULL) as seed
double x = drand48();
The drand48() and erand48() functions return non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0 , 1.0].
Taken from this answer.
I have integer value, and need to round it, how to do that?
105 will be 110
103 will be 100
so classical rounding for decimals? thank you!
One more for you:
int originalNumber = 95; // or whatever
int roundedNumber = 10 * ((originalNumber + 5)/10);
Integer division always truncates in C, so e.g. 3/4 = 0, 4/4 = 1.
I don't know the exact Objective-C syntax, byt general programming question. C-style:
int c = 105;
if (c % 10 >= 5) {
c += 10;
}
c -= c % 10;
No floating point calculations required.
One way to solve this:
rounded = (value + 5) - ((value + 5) % 10);
Or slightly modified:
rounded = value + 5;
rounded -= rounded % 10;
See here: Rounding numbers in Objective-C
You could support floats or express your ints as floats (105.0).