Trouble on "If" statement on TI-84 Plus C Silver Edition - ti-basic

I've got a small code in TI BASIC on my TI-84 Plus C Silver Edition calculator that will determine correct dosage of drugs based on the patient's weight. For example, if aspirin is given at 5 mg per kg of patient weight (it isn't), then the code should tell me to give a 100kg patient 500mg of aspirin.
However, the code is solving for every possible drug. Here it is:
PROGRAM:DRUG1
:Input "PATIENT WEIGHT: ",W
:Input "AGENT NAME: ",A
:If A=IPPI
:Disp "DOSAGE",W*2
:If A=NEVO
:Disp "DOSAGE", W*0.5
So in this case, the two drugs are IPPI and NEVO. If I give a patient weight of 100kg, and choose IPPI, then I would expect to see
DOSAGE 200
However, what I do see is
DOSAGE 200
DOSAGE 50
so apparently both "if" statements are running, even though I've given a only one value (IPPI). [The same error occurs when I set A as NEVO].
I've tried enclosing both If statements within Then...End as well, so the code would look like:
PROGRAM:DRUG1
:Input "PATIENT WEIGHT: ",W
:Input "AGENT NAME: ",A
:If A=IPPI
:Then
:Disp "DOSAGE",W*2
:End
:If A=NEVO
:Then
:Disp "DOSAGE", W*0.5
:End
but that changes nothing.
I'm pretty new to BASIC, so I'm sure there's a simple error that I can't see, but I'm stumped at the moment.

You need to change the second Input command so the information is stored to a string instead of the numeric variable A. TI-84 series calculators have ten string variables in the [VARS][7] menu for this purpose.
Note also that you must compare the string against the string "IPPI" rather than the sequence of letters (numeric variables) IPPI. So your code could be:
:Input "PATIENT WEIGHT: ",W
:Input "AGENT NAME: ",Str1
:If Str1="IPPI"
:Disp "DOSAGE: ",W*2
:If Str1="NEVO"
:Disp "DOSAGE: ",W*0.5
or more concisely:
:Input "PATIENT WEIGHT: ",W
:Input "AGENT NAME: ",Str1
:Disp "DOSAGE:"
:If Str1="IPPI"
:Disp 2W
:If Str1="NEVO"
:Disp .5W

You're trying to use variable names as strings.
:If A=IPPI
This isn't comparing a string to "IPPI", it's comparing a numeric variable A to the numeric value I*P*P*I, which I'm guessing results in 0 in your case.
Similarly, when you take input, if you enter IPPI, it's going to multiply those variables and assign A to be that product.
You'll need to use a string variable and quotes.

The main problem with your program is that you aware assigning a string to a variable that only supports numbers. That leaves the new value of the variable the Boolean value of the string, True, which in the case of TI-BASIC is the value, 1. To fix this you need to assign it to a variable which supports characters in a string, in this case you can use STR1.

Related

Syntax error on simple If Else

I get an error at the 'Else' on a TI-84 Plus.
I can't figure out why this doesn't work.
I'm writing a GCD program just as an exercise in programming a TI calculator.
It's recursive (or as recursive as TI-BASIC gets).
If B=0
Disp A
Else
C->B
B->remainder(A,B)
A->B
prgmGCD2
TI-Basic is often rather picky about the syntax of if statements.
There are three general formats for an If statement.
Single Statement If
:If <boolean>
:<expression>
Note that <expression> consists of exactly one line of code.
Multi Statement If
:If <boolean>
:Then
:<expresion>
:<expresion>
:End
As opposed to the first option, this option can contain any number of lines of code after the If.
If Else
:If <boolean>
:Then
:<expresion>
:<expresion>
:Else
:<expresion>
:<expresion>
:End
As with the previous option, any number of statements can be put after the If and after the Else.
You are obviously trying to use an if else statement. The correct syntax for this is:
:If B
:Then
:C->B
:B->remainder(A,B)
:A->B
:prgmGCD2
:Else
:Disp A
:End

iPart( and int( returning 0 for 1?

Ok, here's my problem. I wrote an advanced Pythagorean Theorem program, but it apparently is having exceptions. Here's an instance of my problem. When I input A? √(3) and B? 2, I get 0 back. Here's the code:
:Prompt A,C
:(C^2-A^2)->B
:If B<0
:Then
:Disp "THAT IS N
OT A VALID TRIA
ANGLE
:Else
:If iPart(√(B))≠
√(B)
:Then
:Disp "B = √(",B
:Else
:Disp "B = ",√(B)
:End
:End
Therefore, if B = 1, then hypothetically it should output B = 1 but instead it outputs:
A=? √(3)
C=? 2
B = √(
1
Done
What am I doing wrong and how can I fix it?
When I quickly evaluate your program, it seems to work correctly when you get B≠1. For example if I want to calculate the famous 3,4,5 - triangle it shows:
A=?4
C=?5
B=
3
Done
Apparently the iPart( doesn't work correctly with √(1). You could include an extra statement to the If iPart( ... statement to rule this out. Like this.
:...
:If iPart(√(B))≠√(B) and B≠1
:...
Besides that I think the program looks cleaner and nicer if you use the Input, ClrHome and Output( commands.
:ClrHome
:Input "A: ",A
:Input "C: ",C
:(C^2-A^2)->B
:If B<0
:Then
:Output(4,1,"THA
T IS NOT A")
:Output(5,1,"VAL
ID TRIANGLE")
:Else
:If iPart(√(B))≠
√(B) and B≠1
:Then
:Output(3,1,"B:
√( )")
:Output(3,5,B)
:Else
:Output(3,1,"B:")
:Output(3,5,√(B))
:End
:End
:Pause
:ClrHome
Now the results screen looks something like this:
A: √(3)
C: 2
B: 1
I think this is cleaner, with the 3 aligned istead of in the bottom right corner. When you press ENTER everything will remove itself from the screen (due to the Pause command).

Multiplying variables in Ruby?

I'm trying to create a simple pay predictor program.
I am capturing two variables, then want to multiply those variables. I have tried doing
pay = payrate * hourrate
but it seems not to work. I was told to put pay in a definition, then I tried to display the variable but it still didn't work. When I looked at the documentation, it seems that I am using the correct operator. Any guesses?
# Simple Budgeting Program
puts "What is your budget type?\nYou can say 'Monthly' 'Weekly' or 'Fortnightly'"
payperiod = gets.chomp
case payperiod
when "Monthly"
puts "You are paid monthly"
when "Weekly"
puts "You are paid weekly"
when "Fortnightly"
puts "You are paid every two weeks."
else
puts "You did not input a correct answer."
end
puts "What is your hourly rate?\n"
payrate = gets.chomp
puts "How many hours have you worked during your pay period?\n"
hourrate = gets.chomp
def pay
payrate * hourrate
end
puts "#{pay}"
preventclose = gets.chomp
The def has nothing to do with it. payrate and hourrate are strings and * means a very different thing to strings. You need to convert them to numbers first with to_i or to_f.
payrate.to_f * hourrate.to_f
You declared pay rate and hour rate as strings. In Ruby, you cannot multiply strings by other strings. However, in Ruby there are type conversions. Ruby's string class offers a method of converting strings to integers.
string = "4"
string.to_i => 4
In your case, you first need to convert BOTH strings to an integer.
def pay
payrate.to_i * hourrate.to_i
end
Here's some great information about strings.
http://www.ruby-doc.org/core-2.1.2/String.html
Hope this helps
Coercing Strings into Numbers, and Back Again
Kernel#gets generally returns a string, not an integer or floating point number. In order to perform numeric calculations, you need to coerce the string into a number first. There are a number of ways to do this, but the Kernel#Float method is often safer than String#to_i because the Kernel method will raise an exception if a string can't be coerced. For example:
print 'Pay Rate: '
rate = Float(gets.chomp)
print 'Hours Worked: '
print hours = Float(gets.chomp)
Of course, operations on floating point numbers can be inaccurate, so you might want to consider using Kernel#Rational and then converting to floating point for your output. For example, consider:
# Return a float with two decimal places as a string.
def pay rate, hours
sprintf '%.2f', Rational(rate) * Rational(hours)
end
p pay 10, 39.33
"393.30"
#=> "393.30"

Factoring program (TI-84 plus)

My Program, just learning how to code calculators today, is not giving me any response but
"DONE"
PROGRAM:FACTORS
:ClrHome
:Input "A=", A
:Input "B=", B
:Input "C=", C
:For(D,1,100,1)
:For(E,1,100,1)
:If (D*E)=C and (D+E)=B
:Stop
:End:End:End
:Disp D
:Disp E
Two problems:
1: All of the ":end"s are on the same line. Do a different one for each
2: This is probably the biggest problem: The "stop" command. "Stop" is used to end the program altogether, and go back to regular function. I'm assuming what you want to do is make it stop looping once D*E=C and once D+E=B. In that case, you can do one of two things: write the breakout code into a repeat loop; for instance
:ClrHome
:Input "A=", A
:Input "B=", B
:Input "C=", C
:For(D,1,100,1)
:For(E,1,100,1)
:Repeat (D*E)=C and (D+E)=B
:End
:End
:End
:Disp D
:Disp E
Or, you can use a Goto command
:If (D*E)=C and (D+E)=B
:Goto Lbl A
And further down in your code, you would put the "Lbl A" above where you wanted it to display your variables
The problem you have is that stop ends the program entirely instead of just breaking the loops. To fix this, instead or using For loops, you could use Repeat loops:
:1→D
:Repeat (D*E=C and D+E=B) or D=100
::1→E
::Repeat (D*E=C and D+E=B) or E=100
:::E+1→E
::End
::1+D→D
:End
You can ignore the extra colons, they are just there for clarity, but if you leave them the code will still work because they function identically to newlines.
The Repeat loops will break by themselves when the condition D*E=C and D+E=B is met, but you have to handle the initialization and incrementing of the variables E and D yourself.
Also note that your factoring algorithm can fail if A does not equal one. Consider dividing both B and C by A, and then outputting A as a constant factor.
Another error with your code is that you have too many End statements, but fixing this would not fix the program, and it would still exit at the Stop. An If without a Then does not need an End, but only one line will be run if the condition is true. For example:
:If <condition>
:<one statement>
or
:If <condition>
:Then
:<statement 1>
:<statement 2>
:<statement ...>
:<statement n>
:End

ROR How to best handle nil in custom validations

I have this custom validations that throws an "undefined method `>' for nil:NilClass" when ever birthday is not set because birthday is nil.
validate :is_21_or_older
def is_21_or_older
if birthday > 21.years.ago.to_date
errors.add(:birthday, "Must 21 Or Older")
end
end
I already have validates_presence_of for birthday so is there a way to have is_21_or_older called only after validates_presence_of passes?
Rails runs all validators independently, in order to give you an array of all the errors at once. This is done to avoid the all too common scenario:
Please enter a password.
pass
The password you have entered is invalid: it does not contain a number.
1234
The password you have entered is invalid: it does not contain a letter.
a1234
The password you have entered is invalid: it is not at least six characters long.
ab1234
The password you have entered is invalid: you cannot use three or more consecutive characters in a sequence.
piss off
The password you have entered is invalid: it does not contain a number.
There are two things you can do, that I know of. Either include everything under your custom validator, in which case everything is under your control, or use the :unless => Proc.new { |x| x.birthday.nil? } modifier to explicitly restrict your validator from running under the circumstances it would break. I'd definitely suggest the first approach; the second is hacky.
def is_21_or_older
if birthday.blank?
errors.add(:birthday, "Must have birthday")
elsif birthday > 21.years.ago.to_date
errors.add(:birthday, "Must 21 Or Older")
end
end
Maybe an even better approach is to keep the presence validator, just exit your custom validator when it sees the other validator's condition is failed.
def is_21_or_older
return true if birthday.blank? # let the other validator handle it
if birthday > 21.years.ago.to_date
errors.add(:birthday, "Must 21 Or Older")
end
end

Resources