Find lowest value in a set of variables

New to FreeBASIC? Post your questions here.
dchapman
Posts: 19
Joined: Apr 01, 2010 9:44
Location: Dallas Texas

Find lowest value in a set of variables

Post by dchapman »

[using -lang qb]

Let's say I have four variables, and assigned each one a random integer value.

Var1%
Var2%
Var3%
Var4%

I want to find the lowest value, discard that variable, and sum the remaining three. Then, make a new variable (Total1%) with value set to the sum.

I came up with a basic IF statement:

Code: Select all

IF Var1% < Var2% AND Var1% < Var3% AND Var1% < Var4% THEN
   Total1% = Var2% + Var3% + Var4%
And if I repeat that statement for each variable in the list, I'll get my desired sum. UNLESS there are two variables that have the same value. Then my IF routine won't work.

Ideas?
agamemnus
Posts: 1842
Joined: Jun 02, 2005 4:48

Post by agamemnus »

Use <=.
square1
Posts: 97
Joined: Nov 12, 2007 2:27

Post by square1 »

This is how I'd do it. (assuming that if two or more variables have the lowest value, you only want to exclude one of them)

Code: Select all

Dim As Integer x,min,n,total

Randomize Timer

min=999999999'this needs to be higher than the variables are going to be

n=4'number of different variables

dim As Integer v(n)

For x = 1 To n
	v(x)=Int(Rnd*100)
	Print x,v(x)
Next x

For x = 1 To n
	If min>v(x) Then min=v(x) End If
	total=total+v(x)'add them all up
Next

Print 
Print
Print total;" - ";min;" = ";

total=total-min'subtract smallest value

Print total
Sleep
By using an array, your code becomes scalable and you can use it for more than 4 different variables without having to type more lines.
dchapman
Posts: 19
Joined: Apr 01, 2010 9:44
Location: Dallas Texas

Post by dchapman »

Well, here's what I came up with using <=

Code: Select all

chooseinput:
cls
print
input "Choose input method: (r)andom or (p)reset? ", chip$
select case lcase$(chip$)
	case "r"
		goto gennum
	case "p"
		goto usernum
End Select


gennum:
randomize timer

num1% = int(rnd * 6) + 1
num2% = int(rnd * 6) + 1
num3% = int(rnd * 6) + 1
num4% = int(rnd * 6) + 1

cls
print
print "1st #: "; num1%
print
print "2nd #: "; num2%
print
print "3rd #: "; num3%
print
print "4th #: "; num4%
print

goto numdrop

usernum:
cls
print
input "1st Number? ", num1%
print
input "2nd Number? ", num2%
print
input "3rd Number? ", num3%
print
input "4th Number? ", num4%
print

numdrop:
IF num1% <= num2% AND num1% <= num3% AND num1% <= num4% THEN
	numsum% = num2% + num3% + num4%
	print "Kept: 2 3 4"
	goto showsum
EndIf
IF num2% <= num1% AND num2% <= num3% AND num2% <= num4% THEN
	numsum% = num1% + num3% + num4%
	print "Kept: 1 3 4"
	goto showsum
EndIf
IF num3% <= num1% AND num3% <= num2% AND num3 <= num4% THEN
	numsum% = num1% + num2% + num4%
	print "Kept: 1 2 4"
	goto showsum
EndIf
IF num4% <= num1% AND num4% <= num2% AND num4% <= num3% THEN
	numsum% = num1% + num2% + num3%
	print "Kept: 1 2 3"
	goto showsum
EndIf
print

showsum:
print
print "Sum = "; numsum%
print
input "Again? (y/n) ", repeat$
if lcase$(repeat$) = "y" then
	GOTO chooseinput
endif
It doesn't do so badly until you enter something like 6 6 6 5 for the numbers. It will erroneously keep the last number and discard a 6.

Thanks square1, I'll take a look and try to figure out what you did there :)
agamemnus
Posts: 1842
Joined: Jun 02, 2005 4:48

Post by agamemnus »

You have "num3" in your code. It's not the same as "num3%".

Anyway I wouldn't do it like that. I'd use a loop and an array, eg:

Code: Select all

dim as integer i, minIndex
dim as uinteger min, myArray(0 to 5)

' Populate myArray with random values.
for i = 1 to ubound(myArray)
 myArray(i) = int(rnd*100)
next i

min = myArray(0): minIndex = 0 ' Sets the baseline minimum value.
for i = 1 to ubound(myArray)
 if myArray(i) < min then myArray(i) = min: minIndex = i
next i
Last edited by agamemnus on Apr 08, 2010 8:04, edited 1 time in total.
dchapman
Posts: 19
Joined: Apr 01, 2010 9:44
Location: Dallas Texas

Post by dchapman »

Good job on finding that mistake. Seems to work now.

However, square's code is a lot cleaner and I'm going to learn more about arrays so I can attempt something similar.
agamemnus
Posts: 1842
Joined: Jun 02, 2005 4:48

Post by agamemnus »

Yep, I just added an example to the post above. It's a bit different than square's code -- it sets the initial min value as the first value in the array so you don't need an artificial large min value.
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Post by anonymous1337 »

You can (unformally) think of arrays as lists. Or, if you're familiar with the concept in math, sets.

These two pieces of code are identical, for a finite number of practical purposes:

Code: Select all

'' our list of numbers
dim as integer foo1 = 0
dim as integer foo2 = 5
dim as integer foo3 = 10
dim as integer foo4 = 15
dim as integer foo5 = 20

'' our highest number
dim as integer highest = 0

'' find our highest number
if( foo1 >= highest ) then highest = foo1
if( foo2 >= highest ) then highest = foo2
if( foo3 >= highest ) then highest = foo3
if( foo4 >= highest ) then highest = foo4
if( foo5 >= highest ) then highest = foo5

Code: Select all

'' our list of numbers
dim as integer foo(0 to 4)
for i as integer = 0 to 4
   foo(i) = i*5
next

'' our highest number
dim as integer highest = 0

'' find our highest number
for i as integer = 0 to 4
    if( foo(i) >= highest ) then highest = foo(i)
next
Where foo(i) means, in laymen terms, "Get me the i'th number from the list foo".
In programming, we say this more generally as, "Return, get, or access the variable in the i'th index of foo()".


How familiar are you with algebra? I can explain the benefit of using foo(i) over foo1, foo2, ..., fooN in algebraic terms, because it's just like the benefits of algebra over elementary arithmetic.

In arithmetic, we say this: 4 + 5 = 12. Cool, but what if we wanted to add another number, or change the numbers we add? We'd have to change both sides of our equation. This is like using an if statement for each variable you create. Very unintuitive:

Code: Select all

dim as integer foo1 = 0
dim as integer foo2 = 0

if( foo1 > foo2 ) then print "foo1 > foo2"

dim as integer foo3 '' uh oh, now I need another if statement!
if( foo3 > foo2 ) then print "foo3 > foo2"
Algebra, however, says: a + b = c. Use any integers as a or b and we will always get integer c. This allows us to introduce the concept of algorithms - general methods of algebraic problem solving. Here's an example:

for all integers i in set foo, let a be the sum of i. Or, in code:

Code: Select all

'' create our list, or set foo.  We call these arrays in programming.
dim as integer foo()

'' create a randomly sized array, from 1 to 40 elements.  0 is the first index of our array.
'' rnd() means random and always returns a value less than 1.
redim foo(0 to rnd() * 40)

'' fill our array with random data - ubound(array) gives us the last index of an array.  lbound(array) gives us the first index, but we don't need it here.
for i as integer = 0 to ubound(foo)
    foo(i) = rnd() * 100
next

'' get the sum of all elements in array foo
dim as integer a = 0
for i as integer = 0 to ubound(foo)
    a += foo(i)
next

'' print our sum
print "The sum of all integers in array foo: " & a
sleep
Instead of writing rules for one, two, etc. integers, we can write code which will work with any number of integers. Arrays help us do this.
j_milton
Posts: 458
Joined: Feb 11, 2010 17:35

solution without array

Post by j_milton »

I would certainly agree with anonymous1337 and others that using an array is the most flexible way to solve this problem. But if for some reason you did not want to you could do it just with "if" statements this way

Code: Select all

t = v1 + v2 + v3 + v4
x = v1
if v2 < x then
  x = v2
endif
if v3 < x then
  x = v3
endif
if v4 < x then
  x = v4
endif
t = t - x
dchapman
Posts: 19
Joined: Apr 01, 2010 9:44
Location: Dallas Texas

Post by dchapman »

Wow. Thanks a million guys, you've really done a great job providing example code and explanations. I'm still looking everything over and trying to understand the concepts.

Couple of questions:

anonymous1337 there were two lines in your code that really threw me.

Code: Select all

    a += foo(i)

Print "The sum of all integers in array foo: " & a
What does "+=" mean?
I've never seen anything like that in the tutorials.

And how about "& a"
Haven't seen that one either. What I've learned to do so far to print variables is

Code: Select all

PRINT "Say something here: "; myvariable
j_milton, thanks. Actually you helped me understand the previous code samples--I didn't catch on to the concept of setting an arbitary integer equal to the lowest value, then subtracting it from the sum of all generated integers. Makes perfect sense. I was coming at it from more or less a reverse angle. Heh.

~David
j_milton
Posts: 458
Joined: Feb 11, 2010 17:35

Post by j_milton »

these 2 lines do the same thing

a = a + 7

a += 7

also work with subtraction, these 2 lines do the same thing:

b = b -4

b -= 4

Its just a way to save some typing

& is the concatenation operator. It joins 2 strings together

a = "hello"
b = " world"
c = a & b
' c now contains "hello world"

+ can also be used the same way with strings, it joins them rather than numerically adding them as it does with numbers, but it is easier to read code to use the & symbol, since this only has one meaning.
vdecampo
Posts: 2992
Joined: Aug 07, 2007 23:20
Location: Maryland, USA
Contact:

Post by vdecampo »

@dchapman

var += is a shortcut for var = var +

so

a+=1 is the same as a=a+1

The & var is the same as str(var) for printing.

-Vince
dchapman
Posts: 19
Joined: Apr 01, 2010 9:44
Location: Dallas Texas

Post by dchapman »

All right. Learned a lot in this thread! Combining what I learned, here's what I came up with.

But, I'm having an error. For some reason, the DISPTOTAL section doesn't work. The program exits after the last run of the main loop. I've looked over it again and again. I snipped the code out and saved it as a test.bas, and ran it, and it runs fine on its own. Baffling.

Code: Select all

'' Declare variables
DIM as integer rawnum(1 to 4), savenum(1 to 6), totalnum, i, dropnum, maini, x 
DIM as string rpt

''Main program loop. Process 6 times

GROUNDZERO:

FOR maini = 1 to 6

	CLS
	RANDOMIZE TIMER
	PRINT
	PRINT "Generating raw numbers..."
	PRINT

'' Loop to generate random values for rawnum
	i = 0
		FOR i = 1 to 4
			rawnum(i) = int(rnd * 6) + 1
		Next

'' Display results
	PRINT "Generated: ";
		FOR i = 1 to 4
			PRINT rawnum(i);" ";
		Next

'' Get lowest value
	dropnum = rawnum(1)
	FOR i = 1 to 4
		IF dropnum >= rawnum(i) THEN
			dropnum = rawnum(i)
		EndIf
	Next

'' Sum everything
		FOR i = 1 to 4
			totalnum += rawnum(i)
		Next

'' Subtract lowest
	totalnum -= dropnum

'' Display
	PRINT
	PRINT "Total: "; totalnum
	PRINT
	PRINT "Any key to continue..."
	SLEEP

'' Save the total in a keeper variable (main loop)
	savenum(maini) = totalnum

'' Reset variables
	totalnum = 0
	i = 0
	dropnum = 0
	FOR x = 1 to 4
		rawnum(x) = 0
	Next x

NEXT maini

'' End Main Loop

DISPTOTAL:
CLS
PRINT
PRINT "Final totals"
PRINT "------------"
PRINT "A: "; savenum(1)
PRINT "B: "; savenum(2)
PRINT "C: "; savenum(3)
PRINT "D: "; savenum(4)
PRINT "E: "; savenum(5)
PRINT "F: "; savenum(6)
PRINT
INPUT "Again? (y\n) ", rpt
	IF LCASE$(rpt) = "y" THEN GOTO GROUNDZERO
END
square1
Posts: 97
Joined: Nov 12, 2007 2:27

Post by square1 »

The section works for me - funnily enough, it didn't when I ran it the first time, but that was because I used the enter key to move through the rounds of the main loop, which then was picked up by the input statement.

To clear the keyboard buffer after the main loop, you can use

Code: Select all

Do	
Loop Until InKey=""
@agamemnus
it sets the initial min value as the first value in the array so you don't need an artificial large min value.
that was a slap-at-the-forehead-moment :)
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Post by anonymous1337 »

Your code looks fine. It could be quitting because a space or other character is present when you get INPUT. Clear the keyboard buffer as square1 suggested, right before your input statement. (Loop through inkey until it returns "", which is the same as returning nothing.)

Pro Tips: Compile with the -exx flag to automatically detect out of bounds array access. Also, you don't have to reset i because for...next sets it for you.
Post Reply