CHAPTER 6

Mathematical
Operations

Chapter Objectives

By the end of the chapter, readers will be able to:

images  Distinguish between well-formed and malformed mathematical expressions.

images  Relate the use of l-value and r-value to mathematical expressions.

images  Understand and use standard arithmetic operators.

images  Understand the order of precedence.

images  Understand the differences between pre- and post-increment and decrement operators.

images  Distinguish between a counter and an accumulator.

images  Use some predefined mathematical functions.

images  Use type-casting techniques.

Introduction

In Chapter 2 we discussed the overall components that most procedural programs follow: Input → Process → Output. In Chapter 5 we explored the input and output pieces of the puzzle. This chapter examines mathematical expressions that are crucial to the process portion of many programs.

6.1 Mathematical Expressions

Mathematical expressions are not unfamiliar. Since our first algebra class, we have seen mathematical expressions involving variables. C++ mathematical expressions have a few more rules, but conceptually they are the same as what you already know. For example, in mathematics, the following equation is valid.

0 = −4y + 5

However, this expression violates a couple important C++ rules. First, every operation must be represented by an operator. The “4y” implies multiplication in math, but all it would do in C++, and most other programming languages, is produce a syntax error. Second, the left side of the equals sign must be a variable. Placing either a literal, in this case 0, or a constant on the left side of the assignment operator (=) produces a syntax error.

Not to pick on mathematicians, but how many ways can you represent multiplication in a mathematical expression? Here are just a few of the different methods mathematical expressions can denote multiplication.

1. −4y

2. −4 · y

3. −4 × y

4. −4 * y

In C++, there is only one valid way to represent each mathematical operation. Example 4 would be the only valid, syntactically correct expression because the asterisk is the only operator that represents multiplication in C++.

We also noted that in C++, the left side of the assignment operator must be a variable. To be more technical, the left side of the assignment operator must represent an appropriate l-value. An l-value is nothing more than a variable location, or a place to store data. The assignment operator changes the value stored in the variable on the left with the results of the expression on the right, called the r-value. The r-value is simply the results of any expression or data contained within a variable, constant, or literal.

There are two types of mathematical operators in C++: unary and binary. Although this might be intimidating at first glance, the difference is simple: a unary operator has one operand, while a binary operator has two operands. In our previous example, “−4 * y”, the negation operator (−) is a unary operator with “4” as its operand. The multiplication operator (*) has two operands, “4” and “y”.

As previously discussed, every variable contains a value whose size is based on the number of bytes reserved for the data type specified. Most values can be stored as more than one data type. For example, the value 10 can be stored as an int, float, double, or even a char because any value can automatically be stored in a variable with a large enough data type. This is called a widening conversion.

The opposite type of conversion is called a narrowing conversion. This occurs when a value is stored in a variable having a smaller data type. You may lose information in a narrowing conversion, but not in a widening conversion. For example, the value 10.5121212116 is treated as a double because it is a numeric literal. If we tried to store that value into a float, we could possibly lose significant data because a float is a smaller data type than a double. For safety purposes, the data type of the l-value should match the largest data type associated with the r-value.

Another thing to be careful of is to not store floating-point numbers in an integer variable. These are two different types of data with different memory representations. Therefore, trying to store a float or a double into an int will result in a compiler warning. The rule of thumb is, if the r-value contains a decimal number, the l-value should be a variable declared with a floating-point data type.

Section 6.1 Exercises

For each of the following statements, identify which ones are valid in C++. If the statement is invalid, state why it is invalid. Assume all variables are declared and initialized.

1. y = 5x + 1;

2. x2 + 2x + 1 = 0;

3. x = 5 * a + 4;

4. 0 = -15 * b;

6.2 Assignment Operator (=)

In its most elementary form, the assignment operator simply assigns a single value to a variable. In the example below, the value 123 is assigned to the variable var_a.

var_a = 123;

The r-value, 123, is being assigned to var_a. If var_a already had a value, it would be replaced by 123. The assignment operator is always executed from right to left. As an example, the following statement assigns the value 1 to all five variables.

var_a = var_b = var_c = var_d = var_e = 1;

The following example uses an assignment operator with two variables: var_a and var_b.

var_a = var_b;

After the execution of the statement, the previous value in var_a is replaced with the value in var_b. The variable var_b is assumed to have a valid value; otherwise, both variables will now contain unknown values.

6.3 Standard Arithmetic Operators (+, −, *, /, %)

C++ provides a wide range of mathematical operators for you to use. Table 6.3.1 lists these operators and demonstrates their use.

As noted, these symbols are used for addition, subtraction, multiplication, and division and follow the basic understanding you already have of their functionality. The final symbol (%), the modulus operator, provides the remainder of a division of two integer values. In the following example, the variable var_a will be assigned a value of 2 since 2 would be the remainder after dividing5by3.

var_a = 5 % 3;

Operator Type Description Example
+ Binary Addition a = b + 5;
Binary Subtraction a = b - 5;
Unary Negation (changes sign of value) a = −b;
* Binary Multiplication a = b * 5;
/ Binary Division a = b / 5;
% Binary Modulus (remainder of dividing right operand into left operand) a = b % 5;

Table 6.3.1 Standard arithmetic operators

Be aware that integer division in C++ differs from that in mathematics. In C++, the result of integer division will be an integer. Therefore, the following example will result in zero being assigned to var_a. In math, var_a would be the floating-point equivalent: .555.

var_a = 5 / 9;

One thing you should never try to do is divide by zero. Doing so results in a runtime error. Later chapters will discuss ways to ensure that this error doesn't happen.

STYLE NOTE  Notice the spacing in the Example column of Table 6.3.1. A space should be placed between a binary operator and its operands. However, we suggest you not place spaces between a unary operator and its operand. Following this form of spacing greatly increases the readability of your code.

Section 6.3 Exercises

What is stored in the variable a in each question?

1.  a = 5 + 10 * 2;

2.  a = (5 + 10) * 2;

3.  a = 5;

a = a + (5 + 10) * 2;

4.  a = 10 % 5;

5.  a = 10 % 3;

6.  a = 5.2 % 2.3;

7.  2 - 5 + 7 = a;

Section 6.3 Learn by Doing Exercises

1.  Write a program that converts the following expressions to legal C++ syntax.

a.  x2 + 3x + 2 = c

b.  images

c.  images

2.  Write a program that accepts as input a value representing U.S. currency. Use the Internet to search for the currency exchange rates to convert this value to the following currencies:

a.  Euro

b.  Canada

c.  Mexico (pesos)

d.  Japan (yen)

e.  India (rupees)

f.  Russia (rubles)

6.4 Increment and Decrement Operators (++, −−)

The increment (++) and decrement (−−) operators are unary operators that increase or decrease their operand's value by one. The two statements shown in Example 6.4.1 are equivalent.

images

The increment operator shown in Example 6.4.1 is called a pre-increment operator because the operator appears to the left of its operand. A post-increment or post-decrement operator appears to the right of its operand.

There are some subtle differences between the pre- and post-increment and decrement operators. Used by themselves, there is no difference in the results between the two forms, as shown in Example 6.4.2.

images

However, when these operators are used as part of a compound statement, the impact on the compound statement is much different. The pre-increment or pre-decrement operator changes the value stored in memory first and then uses the new value in the remainder of the compound statement. The post-increment or post-decrement operator uses the original value in the compound statement but still changes the value in memory when done. Example 6.4.3 demonstrates the differences between the pre- and post- versions of the increment operator.

images

Notice that the second cout statement in Example 6.4.3 displays a 1 because it uses the current value in the variable to print. Remember, though, that the value in memory is still changed by the post-increment operator. The last cout statement in the example displays a 2 because the previous statement modified the memory and changed the value of the variable from 1 to 2.

Make sure you are very comfortable with the pre- and post-increment and decrement operators, as they are commonly used.

Section 6.4 Exercise

1.  Identify the output of the following code fragment.

a = 0;
cout << a++ << endl;
cout << ++a << endl;
cout << a + 1 << endl;
cout << a << endl;
cout << --a << endl;

6.5 Compound Assignment Operators (+=, −=, *=, /=, %=)

We saw in Section 6.2 the standard mathematical assignment operator (=). There are several other assignment operators that incorporate additional functionality. These compound operators combine the functionality of the binary arithmetic operators with the functionality of the standard assignment operator. These operators provide us with another, shorter method to modify the contents of a variable and include +=, −=, *=, /=, and %=. These compound operators are shortcuts that can be used to replace longer statements, as shown in Table 6.5.1.

Notice that the l-value appears as part of the r-value expression when expanded, as shown in the Expansion column of Table 6.5.1. Make special care to understand the order of operations. In the /= and *= expansions, parentheses must be used to achieve the same results as the shortcut, because the entire r-value is evaluated before being applied to the value stored in the variable represented by a.

Operator Statement Expansion
+= a += 5; a = a + 5;
−= a −= b; a = a − b;
*= a *= b + .1; a = a * (b + .1);
/= a /= b + c; a = a / (b + c);
%= a %= 2; a = a % 2;

Table 6.5.1 Compound assignment operators

Section 6.5 Exercises

Convert each of the following statements so that they use either the compound assignment operators or the increment and decrement operators.

int a(10), b(20), c(30);

1.  a = 25 + a;

2.  b = b * a * 2;

3.  b = 1 + b;

4.  c = c % 5;

5.  b = b / a;

Section 6.5 Learn by Doing Exercise

1.  Write a program to prove that the expansions in Table 6.5.1 are correct. Write each compound statement and the expansion to compare the values. As further proof, remove all parentheses from the expansions and rerun. Assume each statement starts with the following values: a = 5; b = 3; c = 10;

6.6 Accumulators Versus Counters

In the previous sections we discussed the increment operator and the compound addition assignment operator. These powerful operators are often used in a couple of rather unique situations. The increment operator works well when used as a counter, while the compound addition assignment operator is often used as an accumulator. A counter adds one to itself whereas an accumulator adds some value other than one.

The distinction between a counter and an accumulator is significant because when solving problems, the terminology used will determine the type of action we need to take. If the solution calls for counting the number of people in a classroom, we would recognize that an increment operation is required. Likewise, if the solution called for summing up a student's loans, we would recognize the need for an accumulator. Example 6.6.1 shows a counter and an accumulator.

images

6.7 Order of Precedence

As you learned in math, there is an established order that must be adhered to when evaluating expressions with multiple operations. This order of operations, or order of precedence, applies to all C++ expressions as well. Table 6.7.1 shows the operators we have covered, listed from highest to lowest order of precedence. The operators with the highest level of precedence are evaluated first within an expression.

If there are multiple operators in an expression with the same level of precedence, they are evaluated from left to right. Parentheses can be used either to clarify an expression or to temporarily change the order of evaluation. If parentheses are nested, the innermost parentheses are evaluated first. One difference between algebraic expressions and C++ expressions is that algebra allows the use of brackets ([ ]) and parentheses interchangeably while C++ only allows parentheses.

postfix ++, postfix - -,
prefix ++, prefix - -, unary -
*, /, %
+,-
=, *=, /=, %=, +=, =

Table 6.7.1 Operator order of precedence

STYLE NOTE  Parentheses should be used to help clarify expressions; however, an expression gets cluttered and can become hard to read if there are too many levels of nested parentheses. If an expression starts to get cluttered, break it up into multiple, smaller expressions to improve the readability of your code. Example 6.7.1 shows a cluttered statement and then a more readable form.

images

Section 6.7 Exercises

What is stored in each of the three variables used in the following mathematical expressions? For each of the exercises, assume the variables have been declared and initialized. Use the initial values for each of these exercises.

int a = 1, b = 2, c = 3;

1.  a = b * c + 3 / 2;

2.  a += ((b - c) * -4 / (a * 2)) + 10 % 2;

3.  a %= ++b - c-- * -.5 / 2;

4.  a -= b-- - --c * -5 / -2;

6.8 Mathematical Functions

There are some common mathematical operations, such as exponentiation, that do not have associated operators. These operations are provided as functions in an external header file called <cmath>. When a function is included in an expression, it is evaluated with the highest level of precedence (i.e., first). The following sections show a few of the more common mathematical functions.

Functions often require the programmer to provide values on which the function will operate. These values are called parameters.

6.8.1 The pow Function

A lot of mathematical equations and formulas use exponentiation. This is easily accomplished in C++ by using the pow function, the syntax of which is shown here.

<l-value> = pow( <base>, <power> );

In mathematics, the preceding syntax would be shown as: lvalue = basepower. The base parameter can be any numeric data type except an int, but the power parameter can be any numeric data type. Some compilers support having an int for the base, but they are less compliant with the current standard. Remember to make sure there is enough room in the l-value to accommodate the results from the function. Example 6.8.1 illustrates how to use the pow function.

images

Notice that Example 6.8.1 does not directly store the result of the pow function in a variable. Instead, the value returned by the pow function is directly used in the expression. The results of the calculation are then assigned into the variable area.

Also notice that the <cmath> header file automatically takes care of the namespace requirements for you. Therefore, once you include the <cmath> header file, all of the functions referenced in the file are available for use.

STYLE NOTE  In Example 6.8.1 we raised the base to the power of two by using the pow function. However, we could have just as easily multiplied the base by itself. In fact, it would have been more efficient to do so. Every time a function is called or executed, there is a certain amount of cost involved. Multiplying the value by itself would have avoided that additional performance degradation. If you are squaring a single variable, it is better and faster to multiply that value by itself.

6.8.2 The sqrt Function

Another function commonly needed relates to finding the square root of a value. The function that accomplishes this task is the sqrt function. The syntax of how to use the function is shown here.

<floating_point_l-value> = sqrt( <floating_point_value> );

Although you might expect that the parameter passed to the sqrt function could be any data type, it actually needs to be a floating-point value (float, double, or long float). Therefore, if you need to take the square root of an integer, use type casting to convert the integer to a floating-point value (discussed further in Section 6.9). Also, remember your math! It is invalid to take the square root of a negative value. In Visual Studio the value will become “1.#IND”, basically representing an invalid value. Example 6.8.2 demonstrates the sqrt function.

images

6.8.3 The abs Function

In C++, the abs function returns the absolute value of the parameter passed to the function. The syntax of the abs function is shown here.

<numeric_l-value> = abs( <numeric_r-value> );

Example 6.8.3 demonstrates the abs function.

images

In Example 6.8.3, the absolute value is determined first, and then the square root of that value will be calculated. Finally, the square root is assigned to the variable square_root.

Now that you have seen how some of the math functions in <cmath> work, there are many others you can use as needed. Table 6.8.1 shows some additional functions.

There are many math functions available besides those shown in Table 6.8.1. Use your online help or the Internet to find additional functions.

Section 6.8 Exercises

What value is stored in the variable a after each mathematical expression?

1.  a = sqrt( 9.0 );

2.  a = sqrt( -9.0 );

Function Description
sin Returns a floating point value that is the sine of the floating-point parameter.
cos Returns a floating point value that is the cosine of the floating-point parameter.
tan Returns a floating point value that is the tangent of the floating-point parameter.
asin Returns a floating point value that is the arcsine of the floating-point parameter.
log Returns a floating point value that is the natural log of the floating-point parameter.
ceil Returns the smallest integer greater than or equal to the floating-point parameter.
floor Returns the largest integer less than or equal to the floating-point parameter.

Table 6.8.1 Mathematical functions

3.  a = pow( 2.0, 5 );

4.  a = pow( 2.0, -2 );

5.  a = ceil( 5.1 );

6.  a = ceil( 5.9 );

7.  a = floor( 5.1 );

8.  a = floor( 5.9 );

9.  a = sqrt( pow( abs( -2 ), 4 ) );

Section 6.8 Learn by Doing Exercise

1.  Write a program that accepts as input two sides of a right triangle. Solve for the length of the hypotenuse using the Pythagorean theorem, which states that the square of the hypotenuse is equal to the sum of the squares of the two sides, or c2 = a2 + b2, where c is the hypotenuse. Display the length of all three sides.

6.9 Type Casting

There are some situations that require us to convert from one data type to another. This technique, called type casting, can be used to force a value to be converted from one type to another. Example 6.9.1 demonstrates how to use one form of type casting to convert the value returned from the pow function from a double to an int.

images

The conversion forces the type change. However, the change may not always be considered safe. Although type casting helps avoid conversion warnings, it sometimes just hides an underlying problem. There are often very valid reasons why the compiler issued a warning; therefore, care should be taken when using type casting. Example 6.9.2 demonstrates other uses of the static_cast.

images

images

In Example 6.9.2, the first cast converted a double to a float. The second cast converted an int to a char, in essence converting an ASCII value to its associated character value. It is important to understand that type casting does not change the contents or data of the variable being cast.

There are other, older, forms of type casting. Example 6.9.3 shows these older styles.

images

Although still available in many environments, be sure to only use the first form from Example 6.9.3 in C programs. The second example is seen in a lot of legacy code but should be avoided when writing programs. When writing C++ code, use static_cast when converting between primitive data types.

6.10 Problem Solving Applied

In the previous chapters an attempt was made to show and discuss the steps necessary for designing and developing a complete solution. In the last chapter, an additional section was added showing how easy it is to convert an algorithm—assuming it was correct—to actual source code. From this point on, a few modifications to the material presented in this section will be made. First, we will continue to focus on the design and implementation details, but will make it a point to stress the latest concepts and material covered within the chapter. Second, in our translation of the algorithm to source code, we will include only the newer concepts and statements just covered.

Problem statement: A friend has asked you to provide a short report that displays the results for a number of different mathematical calculations and functions. Your friend would like a program that can achieve the following functionality:

images  Find the average of a series of numbers

images  Find the remainder when dividing one number by another

images  Raise a number to a power

images  Find the square root of a number

images  Find the sine of a number

Be sure your report, or output, correctly presents the results of these calculations.

Requirement Specification:

Input(s):

Input Type Data Source
Decimal Test1 Keyboard
Decimal Test2 Keyboard
Decimal Test3 Keyboard
Integer TotalSeconds Keyboard
Decimal Base Keyboard
Decimal Power Keyboard
Decimal Discriminant Keyboard
Decimal Angle Keyboard

Output(s):

Output Type Data Destination
Decimal Average Screen
Integer Minutes Screen
Integer RemSeconds Screen
Decimal RaisedValue Screen
Decimal SquareRoot Screen
Decimal Sine Screen

Constants:

No constants are used within this problem.

Design:

images

6.11 C—The Differences

The only differences between C and the C++ techniques discussed in this chapter involve the mathematical functions just presented. First, the header file you would need to include is <math.h>. Next, the pow function is always passed two double values and returns a double. Likewise, the sqrt function is always passed a double and returns a double.

The biggest difference, however, is the process required to find the absolute value of a number. There are separate functions for each numeric data type. Table 6.11.1 shows the functions and their associated data types.

Another difference is how C type-casts. In C++, the static_cast keyword is used to convert from one data type to another. C, however, places parentheses around the target data type, placed in front of the value to be converted. Example 6.11.1 clearly shows the differences between a C++ and a C cast.

images

Table 6.11.1 C absolute value functions

images

6.12 SUMMARY

This chapter presented a variety of topics, most related to developing expressions and using existing mathematical functions. Along the way, we presented the standard C++ arithmetic operators—the fundamentals of which you were already familiar with, such as operator precedence. Next, we demonstrated some crucial aspects associated with using the assignment operator, and took a quick peak at the core characteristics associated with variables, including examining l-values and r-values.

We presented pre- and post-increment and decrement operators, as well as the differences between them. We also provided a descriptive comparison between counters and accumulators and which operators are used in these types of expressions. Next, we presented several mathematical functions that you can use in developing your own programming solutions. The chapter concluded with a discussion of type casting and how this technique forces data type conversion.

You will have plenty of time to practice with these various operators and functions, not only in the following exercises but as the text progresses. Much of the material just presented will be used extensively when discussing more advanced concepts later in the text.

6.13 Debugging Exercise

Download the following file from this book's website and run the program following the instructions noted in the code.

images

images

6.14 Programming Exercises

The following programming exercises are to be developed using all phases of the development method. Be sure to make use of good programming practices and style, such as constants, whitespace, indentation, naming conventions, and commenting. Make sure all input prompts are clear and descriptive and your output is well formatted and looks professional.

1.  Calvin is shopping for a circular, above ground swimming pool. He is currently looking at a pool that is 25′ in diameter and 5′ deep. Assume the Klamath Falls Water Department charges $1.80 per unit of water, and a unit is considered 748 gallons. Write a program that determines how much it will cost Calvin to fill his swimming pool. He will want to be able to enter different dimensions each time he runs the program so that he can determine which pool to buy. Here are some formulas and conversions that may help.

1 gallon (U.S.) = 231 cubic inches

1 cubic inch = 1/1,728 cubic foot

volume of a cylinder: πr2h

2.  Paul is building a workshop and has already figured out how much lumber he needs. The following table shows the cost at one of the local lumberyards for each item as well as the number of items Paul needs. Write a program that creates a report that lists each item, the quantity of each item, the cost per item, and the total cost for that item. The report should also include the total cost of all materials. Because Paul wants to determine which lumberyard will give him the best deal, he will need to be able to specify the cost of each item. Be sure to test your program with the sample data.

Description Cost per Unit Quantity Needed
Joists 75.99 25
2 × 6 8.90 100
2 × 4 4.95 25
4 × 4 12.95 20
4 × 8 sheet plywood 22.00 100

Table 6.14.1 Sample data

3.  Jeanie recently decided to go shopping for a newer 4-wheel drive Jeep to use for commuting to school. She is hoping to put $1,000 or so down on her new purchase. Your job is to develop the necessary program to calculate and display what her payment would be based on the cost of the car, the amount of money she puts down, the time period of the loan, and the interest rate. The formula might look similar to:

images

where P is the principal, DP represents the down payment, r is the interest rate, and m is the number of monthly payments.

4.  Your friend is working with various circle-related calculations and has asked for your help. Your job is to write a short program that will prompt the user to enter the radius from the keyboard. Once you have the radius, calculate and display the circumference and area of the circle. Use 3.14159 for pi.

The formula for the circumference is: C = 2πr

The formula for the area is: A = πr2

6.15 Team Programming Exercise

Remember Troy, the guy from the last chapter who recently joined your team? Well, now he has begun developing the solution for a short program dealing with various math-related operations. He has provided you with a copy of his partially completed pseudocode. Unfortunately, Troy did not get a chance to double-check his work, so you will need to check the accuracy of his algorithm before writing the C++ code. And as you can see, he also did not get the chance to complete all of the details required in the pseudocode related to the processing needed. Your job is to double-check his algorithm; complete the necessary parts related to the processing phase; and write, test, and debug the C++ program.

Display “Some Math Examples”

Prompt “Enter the first (integer) number:”

Read FirstNumber

 

Prompt “Enter the second (integer) number:”

Read SecondNumber

 

Prompt “Enter the third (integer) number:”

Read ThirdNumber

 

Prompt “Enter number (x):”

Read NumberX

 

Prompt “Raise ‘x’ to what power:”

Read PowerNumber

 

—Processing Section - need to finish this up—

SumOfNumbers = FirstNumber + SecondNumber + 3rdNum

 

Display “Your three numbers entered were:”

Display FirstNumber “ ” SecondNumber “ ” ThirdNumber

Display “Sum of the numbers is:”

Display SumOfNumbers

Display “Average of the three numbers is:”

Display AverageOfNumbers

Display “Product of the 3 numbers is:”

Display ProdOfNumber

Display “Square Root of the Sum of the numbers is:”

Display SquareRoot

Display “The remainder of the sum of the numbers / 3 is:”

Display Reminder

Display “** ALL DONE **

6.16 Answers to Chapter Exercises

Section 6.1

1.  Invalid. Each operation has a specific operator. This expression can be rewritten as:

y = 5 * x + 1;

2.  Invalid. This statement has so many problems it needs to be completely rewritten. First, the left side of the assignment operator is not a variable. Second, the multiplication is not being represented correctly; it needs the multiplication operator. Finally, there is no C++ operator to represent exponentiation.

3.  Valid.

4.  Invalid. The left side of the assignment operator must be a variable, not a literal.

Section 6.3

1.  25

2.  30

3.  35

4.  0

5.  1

6.  Invalid expression. The modulus operator cannot be used with floating-point values.

7.  Invalid expression. The left side of the assignment operator must be a variable.

Section 6.4

1.

0

2

3

2

1

Section 6.5

1.  a += 25;

2.  b *= a * 2;

3.  b++; or b += 1;

4.  c %= 5;

5.  b /= a;

Section 6.7

1.  a: 7; b: 2; c: 3

2.  a: 3; b: 2; c: 3

3.  Will not compile because the r-value is a double, which cannot be used with a modulus operator.

4.  a: 4; b: 1; c: 2

Section 6.8

1.  3.0

2.  You cannot take the square root of a negative number.

3.  32

4.  .25

5.  6

6.  6

7.  5

8.  5

9.  4

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.171.125