strange behavior with Coldfusion loops? - coldfusion

Today I have written small program in ColdFusion to find the square root of a number. I found a strange issue. Not sure am I doing any silly mistake ?
<cfscript>
num = 16;
n = 0.0001;
i = 0;
for (i=0;i<num;i=i+n)
{
if((i*i)>num){
i = i - n;
break;
}
}
writedump(i);
</cfscript>
The output is 3.999 instead of 4 when num = 16. Where as when I set it to 36 its output is 6.
Not sure why I am getting 3.999 where as it should be 4.Any suggestion?

I altered your code to output the conditions you are seeing like so:
<cfscript>
num = 16.00;
n = 0.0001;
i = 0;
for (i=0;i<num;i=i+n)
{
writeoutput(i & " i * i = " & (i*i));
writeoutput('<br>');
if((i*i)>num){
i = i - n;
break;
}
}
writedump(i);
writeoutput('<br>');
</cfscript>
This outputs all the numbers and the multiples - a long list. The last 3 lines look like this:
3.9999 i * i = 15.99920001
4 i * i = 16
3.9999
That seems like expected behavior to me. Inside your break code you are reducing the value of i with this line:
i = i - n;
Is that not what you want?

Why do you want to do all the heavy lifting when we can use power of java as below:
<cfset testNumber = 20.50 />
<cfset mathObj = createObject( "java", "java.lang.Math" ) />
<cfset sqrtNumber = mathObj.sqrt(testNumber) />
<cfdump var="#sqrtNumber#"><cfabort>
Output:
4 -> 2
6 -> 2.44948974278
36- > 6
20.50 - > 4.52769256907
As you can see it works on all values including decimals. I hope this helps.
Note: Before passing values to the mathObj.sqrt, you should first check for negative values. You can not have sqrt of negative numbers.
Edit:
As Leigh pointed out there is already a function in CF, you can use that as follows:
<cfset testNumber = 36 />
<cfset sqrtNumber = sqr(testNumber) />
You will get output same as Java version code, only difference is that when you pass negative value in java code, you will get a gibberish value. With CF, you will get an error like this The 1 parameter of the Sqr function, which is now -122.0, must be a non-negative real number.

There is a problem in the if condition. When you use num=36 in that case at 6.001 the if condition gets evaluated and you get 6. But in the case of num=16 the if condition gets evaluated at 4.00 and you get 3.999.
But you may ask why at 4.00 it gets evaluated due to floating point numbers and floating point arithmetic.
Edit:
You can use Newton method to find square root of any +ve number.By this method you can achieve better performance over for loop that you had used.

Related

Python 2 - Division times 10 returns 0 everytime

When the program divides two user inputted numbers, then times that, the program returns 0 every time
correct = input("User, Input the amount of correct answers. :")
points_possible = input("User, Input the amount of points possible. :")
score = correct / points_possible
grade = score * 10
print grade
The expected output
if (1/2) * 10 = 5, but will output 0
If you are using Python 2.7 version, the input that would be taken from the console would always be in the form of strings. So, you'll need to convert it to integers.
#code in Python 3.5
correct = int(input("User, Input the amount of correct answers. :"))
points_possible = int(input("User, Input the amount of points possible. :"))
score = correct / points_possible
grade = score * 10
print(grade)
The reason why you're just getting 0 in Python 2 is that if integers are given then you'll get integer division only. If you want float division, you need to make sure there is a decimal point somewhere so that Python knows it doesn't have to truncate the value to an int.
#code in Python 2.7
correct = float(raw_input("User, Input the amount of correct answers. :"))
points_possible = float(raw_input("User, Input the amount of points possible. :"))
score = correct / points_possible
grade = score * 10.0
print grade
it's because python needs you to make it understand that you divide by a float: you can either add .0 at the end of the diviser or type 10/float(2)

How to use fold statement index in function call

The fold manual gives an example:
input price = close;
input length = 9;
plot SMA = (fold n = 0 to length with s do s + getValue(price, n, length - 1)) / lenth;
This effectively calls a function iteratively like in a for loop body.
When I use this statement to call my own function as follows, then it breaks because the loop index variable is not recognized as a variable that can be passed to my function:
script getItem{
input index = 0;
plot output = index * index;
}
script test{
def total = fold index = 0 to 10 with accumulator = 0 do
accumulator + getItem(index);########## Error: No such variable: index
}
It is a known bug / limitation. Has been acknowledged without a time line for a fix. No workaround available.
Have you tried adding a small remainder to your defined variable within the fold and then pass that variable? You can strip the integer value and then use the remainder as your counter value. I've been playing around with somethin similar but it isn't working (yet). Here's an example:
script TailOverlap{
input i = 0;
def ii = (Round(i, 1) - i) * 1000;
... more stuff
plot result = result;
};
def _S = (
fold i = displace to period
with c = 0
do if
TailOverlap(i = _S) #send cur val of _S to script
then _S[1] + 1.0001 #increment variable and counter
else _S[1] + 0.0001 #increment the counter only
);
I'm going to continue playing around with this. If I get it to work I'll post the final solution. If you're able to get work this (or have discovered another solution) please do post it here so I know.
Thanks!

How to increment a value which could be of either 1 or 2 or 3 decimal digits or without decimal values also?

I have to increment version number in a file. I could pattern match the version no. using following code in a particular string:
if($string =~ /versionName="(\d{1,3}+(\.\d{1,3})?)"/)
Now possibilities of having values are:
1. x{1,3}.x{1,3} (value having up to three decimal value or without decimal also)
Now I have to increment the value accordingly.
If it a value without decimal say 2 then I have to make it 3.
If it is a value having one decimal value say 3.2, then I have to make it 3.3 till 3.9, after that it should be incremented as 4.0
If it is a value having two decimal values say 4.22, then I have to make it 4.23 till 4.99, after that it should be incremented as 5.00
If it is a value having three decimal value say 56.554, then I have to make it 56.555 till 56.999, after that it should be incremented as 57.000
Please let me know if there is any confusion with the question.
I've not done this kind of thing before, so confused right now.
Any help would be greatly appreciated.!!
Basically, you want to ignore the "." when doing the addition.
You can achieve that by multiplying by 10n where n is the number of decimal places before the addition, then by dividing by the same factor, but then you'd need to worry about floating-point precision error.
You can also achieve that by literally removing the "." from the string.
if (my ($unit, $frac) = $num =~ /^([^.]*)\.(.+)/s) {
my $places = length($frac);
$num = "$unit$frac" + 1;
$num = sprintf('%0*d', $places+1, $num); # Handle 0.x
substr($num, -$places, 0, '.');
} else {
++$num;
}
Count the decimal number (1,2, 3) = C. Multiply by 10 exp C. Add one and then divide by 10expC.
Yep?
Example:
10.999
° multiply by 1000 = 10999
° add 1 = 11000
° divide by 1000 = 11.000
If the version contains more than once decimal then we may have some problem ( Ex :- 10.9.9 which should result in 11.0.0 )
I have tried to write a perl snippet which should help
my $version="10 .9.9" ;
$version =~ s/\s+//g ;
my #ver_seg = split("",$version);
my $flag_incr=1;
for (my $i= #ver_seg-1; $i>0 && $flag_incr!=0 ; $i-- )
{
if ( $ver_seg[$i] !~ /\./ )
{
my $temp=$ver_seg[$i];
$temp=$temp+$flag_incr ;
$flag_incr= $temp/10;
$ver_seg[$i]=$temp%10;
}
}
my $version_new=join("",#ver_seg);
print "hi $version_new \n";
taken an example with 10.9.9 .

Why is python skipping a line?

I'm pretty new to Python (just started teaching myself a week ago), so my debugging skills are weak right now. I tried to make a program that would ask a user-submitted number of randomly-generated multiplication questions, with factors between 0 and 12, like a multiplication table test.
import math
import random
#establish a number of questions
questions = int(input("\n How many questions do you want? "))
#introduce score
score = 1
for question in range(questions):
x = random.randrange(0,13)
y = random.randrange(0,13)
#make the numbers strings, so they can be printed with strings
abc = str(x)
cba = str(y)
print("What is " + abc + "*" + cba +"?")
z = int(input("Answer here: "))
print z
a = x*y
#make the answer a string, so it can be printed if you get one wrong
answer = str(a)
if z > a or z < a:
print ("wrong, the answer is " + answer)
print("\n")
#this is the line that's being skipped
score = score - 1/questions
else:
print "Correct!"
print ("\n")
finalscore = score*100
finalestscore = str(finalscore)
print (finalestscore + "%")
The idea was that every time the user gets a question wrong, score (set to 1) goes down by 1/question,so when multiplied by 100 it gives a percentage of questions wrong. However, no matter the number of questions or the number gotten wrong, score remains 1, so finalestscore remains 100. Line 26 used to be:
if math.abs(z)-math.abs(a) != 0:
but 2.7.3 apparently doesn't acknowledge that math has an abs function.
Such a simple accumulator pattern doesn't seem like it would be an issue, even for an older version of Python. Help?
Try score = score - 1.0/questions
The problem is that you're doing integer division, which truncates to the nearest integer, so 1/questions will always give 0.
The problem is that you are using integers for all of your calculations. In particular, when you calculate 1/questions, it truncates (rounds down) to an integer because both values in the calculation are integers.
To avoid this, you could instead use 1.0/questions to make the calculations use floating point numbers instead (and not truncate)

Parsing version numbers to real numbers

I would like to determine if one version number is greater than another. The version number could be any of the following:
4
4.2
4.22.2
4.2.2.233
...as the version number is beyond my control, so I couldn't say how many dots could actually exist in the number.
Since the number is not really a real number, I can't simply say,
Is 4.7 > 4.2.2
How can I go about converting a number, such as 4.2.2 into a real number that could be checked against another version number?
I would preferably like a ColdFusion solution, but the basic concept would also be fine.
This is ripped from the plugin update code in Mango Blog, and updated a little bit. It should do exactly what you want. It returns 1 when argument 1 is greater, -1 when argument 2 is greater, and 0 when they are exact matches. (Note that 4.0.1 will be an exact match to 4.0.1.0)
It uses the CF list functions, instead of arrays, so you might see a small performance increase if you switched to arrays instead... but hey, it works!
function versionCompare( version1, version2 ){
var len1 = listLen(arguments.version1, '.');
var len2 = listLen(arguments.version2, '.');
var i = 0;
var piece1 = '';
var piece2 = '';
if (len1 gt len2){
arguments.version2 = arguments.version2 & repeatString('.0', len1-len2);
}else if (len2 gt len1){
arguments.version1 = arguments.version1 & repeatString('.0', len2-len1);
}
for (i=1; i lte listLen(arguments.version1, '.'); i=i+1){
piece1 = listGetAt(arguments.version1, i, '.');
piece2 = listGetAt(arguments.version2, i, '.');
if (piece1 neq piece2){
if (piece1 gt piece2){
return 1;
}else{
return -1;
}
}
}
//equal
return 0;
}
Running your example test:
<cfoutput>#versionCompare('4.7', '4.2.2')#</cfoutput>
prints:
1
If version 4 actually means 4.0.0, and version 4.2 actually means 4.2.0, you could easily convert the version to a simple integer.
suppose that every part of the version is between 0 and 99, then you could calculate an 'integer version' from X.Y.Z like this:
Version = X*100*100 + Y*100 + Z
If the ranges are bigger or smaller you could use factors higher or lower than 100.
Comparing the version then becomes easy.
Parse each number separately and compare them iteratively.
if (majorVersion > 4 &&
minorVersion > 2 &&
revision > 2)
{
// do something useful
}
// fail here
That's obviously not CF code, but you get the idea.
A version number is basically a period delimited array of numbers, so you can parse both versions into number arrays, and then compare each element in the first array to the corresponding element in the second array.
To get the array, do:
<cfset theArrayofNumbers = listToArray(yourVersionString, ".")>
and then you can do your comparisons.
You can split the string containing the version by periods, then start at the first index and compare down until one is greater than the other (or if they are equal, one contains a value the other does not).
I'm afraid I've never written in coldfusion but that would be the basic logic I'd follow.
This is a rough unoptimized example:
bool IsGreater(string one, string two)
{
int count;
string[] v1;
string[] v2;
v1 = one.Split(".");
v2 = two.Split(".");
count = (one.Length > two.Length) ? one.Length : two.Length;
for (int x=0;x<count;x++)
{
if (Convert.ToInt32(v1[x]) < Convert.ToInt32(v2[x]))
return false;
else if (Convert.ToInt32(v1[x]) > Convert.ToInt32(v2[x])
return true;
} // If they are the same it'll go to the next block.
// If you're here, they both were equal for the shortest version's digit count.
if (v1.Length > v2.Length)
return true; // The first one has additional subversions so it's greater.
}
There is no general way to convert multiple-part version numbers into real numbers, if there is no restriction on the size of each part (e.g. is 4.702.0 > 4.7.2?).
Normally you would define a custom comparison function by creating a sequence or array of version-number parts or components, so 4.7.2 is represented as [4, 7, 2] and 4.702.0 is [4, 702, 0]. Then you compare each element of the two arrays until they don't match:
left = [4, 7, 2]
right = [4, 702, 0]
# check index 0
# left[0] == 4, right[0] == 4
left[0] == right[0]
# equal so far
# check index 1
# left[1] == 7, right[1] == 702
left[1] < right[1]
# so left < right
I don't know about ColdFusion, but in some languages you can do a direct comparison with arrays or sequences. For example, in Python:
>>> left = [4, 7, 2]
>>> right = [4, 702, 0]
>>> left < right
True