Skip to content

Data Types

1 Lecture 1: Binary And Data Encoding

  • Representation of integers in binary are fairly straightforward compared to floating point numbers, strings, irrational numbers, etc.
  • Base 2 = binary, base 10 = decimal, base 16 = hexadecimal.
  • The base of a number is the number of digits in the number system, and then the number is multiplied by the base to the power of the position of the digit. e.g. 123 = 1*10^2 + 2*10^1 + 3*10^0 = 100 + 20 + 3. and 1011 = 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 8 + 0 + 2 + 1 = 11. and 0x1A = 1*16^1 + 10*16^0 = 16 + 10 = 26.
Decimal Binary Hexadecimal
base 10 2 16
digits 0-9 0-1 0-9, A-F
example 123 = 1*10^2 + 2*10^1 + 3*10^0 = 100 + 20 + 3 1011 = 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 8 + 0 + 2 + 1 = 11 0x1A = 1*16^1 + 10*16^0 = 16 + 10 = 26.
  • ASCII:
    • It is a map for translating numbers and characters to binary and vice versa.
    • It is a 8-bit code, so it can represent 2^8 = 256 characters.
    • It was good for English, but not for other languages as they need more than 256 characters.
  • Unicode:
    • There are two flavours of Unicode: UTF-8 and UTF-16 (UTF = Unicode Transformation Format).
    • It uses 16 bits, or 32 bits, to represent characters which is enough for most languages.
  • An Overflow:
    • It happens when you need to carry a bit to the left, but there is no space for it, aka, the number is too big to be represented.
    • An overflow gives the wrong result, as the carried bit is lost.
    • Example: 2 + 2 = 4 in binary is 10 + 10 = 100, but if we only have 2 bits, then 10 + 10 = 00 which is wrong.
  • To represent negative integers in binary, we use:
    • 1 complement: the most significant bit is the sign bit, and the rest of the bits are the magnitude of the number.
    • 2 complement.
  • To represent real numbers (floating point numbers), we use:
    • The memory word is divided into 3 parts: sign, exponent, and mantissa(fraction).
    • For example: 8 bits = 1 bit sign + 3 bits exponent + 4 bits mantissa that is tha maximum number that we can represent is 2^3 -1 = 7 in the exponent, and 2^4 -1 = 15 in the fraction, so 7.15 is the maximum number that we can represent and 7.16 and beyond is an overflow.
    • Fixed point: a fixed number of digits after the decimal point.
    • Floating point: a number of digits after the decimal point that is not fixed.
  • Big Endian/ Little Endian:
    • It is the order of the bytes in the memory.
    • Big Endian: the most significant byte is stored in the smallest address (left to right).
    • Small Endian: the least significant byte is stored in the smallest address (right to left).
    • Example 0123 is stored as 0123 in Big Endian, and 2310 in Little Endian.
    • Little Endian stores numbers backwards (fourteen => |4|1|, forty one => |1|4|) 9
    • In memory, there is not left and right; you can not say this byte represent (tens) and the bight right to it represent (ones) (assuming every digit is stored in one byte) 9
  • To convert a Decimal to a binary:
    • Divide the number by 2, and keep the remainder.
    • Example: 13 = 1101 as 13/2 = 6 remainder 1, 6/2 = 3 remainder 0, 3/2 = 1 remainder 1, 1/2 = 0 remainder 1.
    • Example: 123 = 1111011 as 123/2 = 61 remainder 1, 61/2 = 30 remainder 1, 30/2 = 15 remainder 0, 15/2 = 7 remainder 1, 7/2 = 3 remainder 1, 3/2 = 1 remainder 1, 1/2 = 0 remainder 1.
  • To convert a Binary to a decimal:
    • Multiply each digit by 2 to the power of its position, and add them all together.
    • Example: 1101 = 1\*2^3 + 1\*2^2 + 0\*2^1 + 1\*2^0 = 8 + 4 + 0 + 1 = 13.
    • Example: 1111011 = 1\*2^6 + 1\*2^5 + 1\*2^4 + 1\*2^3 + 0\*2^2 + 1\*2^1 + 1\*2^0 = 64 + 32 + 16 + 8 + 0 + 2 + 1 = 123.
  • To take the 1 complement of a binary number:
    • Flip all the bits.
    • Example: 1101 = 0010.
    • Example: 1111011 = 0000100.
  • To take the 2 complement of a binary number:
    • Take the 1 complement of the number, and add 1 to it.
    • Example: 1101 = 0010 + 1 = 0011.
    • Example: 1111011 = 0000100 + 1 = 0000101.
  • Examples:
// convert 32 to binary to 8 bits
    32 =
        32/2 = 16 remainder 0
        16/2 = 8 remainder  0
        8/2  = 4 remainder  0
        4/2  = 2 remainder  0
        2/2  = 1 remainder  0
        1/2  = 0 remainder  1
        = 00100000

// take the 2 complement of 32
    100000 = 11011111 + 00000001 = 11100000

// find the 2 complement of `00011100`
    00011100 = 11100011 + 00000001 = 11100100


// convert 25 to binary
    25 =
        25/2=12 reminder 1
        12/2=6 reminder 0
        6/2=3 reminder 0
        3/2=1 reminder 1
        1/2=0 reminder 1
        = 00011001

// take the 2 complement of 25
    11001 = 11100110 + 00000001 = 11100111

// convert 128 to 8 digit binary
    128 =
        128/2=64 reminder 0
        64/2=32 reminder 0
        32/2=16 reminder 0
        16/2=8 reminder 0
        8/2=4 reminder 0
        4/2=2 reminder 0
        2/2=1 reminder 0
        1/2=0 reminder 1
        = 10000000

2 Lecture 2: Elementary Data Types

  • Also known as primitive data types.
  • Includes: integers (int, byte, short), floating point numbers(float, double), characters(char), booleans…etc.
Type Size (bits) size (bytes) Description Kind of Data Range of Values
byte 8 1 1 byte signed integer integer -128 to 127
short 16 2 2 bytes signed integer integer -32,768 to 32,767
int 32 4 4 bytes signed integer integer -2,147,483,648 to 2,147,483,647
long 64 8 8 bytes signed integer integer ⨦ -9,223,372,036,854,775,808
float 32 4 4 bytes floating point real
double 64 8 8 bytes floating point real
char 16 2 2 bytes character (unsigned) character All unicode values from 0 to 65535
bool 1 1 bit boolean boolean true or false
  • The 2-byte char type supports UTF-16, but has another flavour which is 4 bytes long and supports UTF-32.
  • The type Enum is considered a primitive type in some languages, and a derived type in others. We will consider it a Elementary type.
  • Computers can only understand integers, so all other types are converted to integers (in a binary format) before being processed.

3 Lecture 3: Composite Data Types

  • It is either Derived or User-defined.
  • Derived types are built from elementary types. Example: Array, Pointer, Function.
  • User-defined types are built from other user-defined types. Example: Struct, Union, Class.
Type Description
Array A collection of elements of the same type. The size must be predefined. Referenced by index.
String An Array of chars.
Struct Also named Record or Class, which all represent Objects.
Reference A pointer to a memory location. The variable is bound to the memory location.

4 LEcture 4: Representing Real Numbers

  • Floating point numbers are represented in Scientific Notation or Exponential Notation.
  • Irrational numbers are represented as approximations.
  • Required things to represent a floating point (example: 123 * 10^(-3)):
    • Sign: one bit to represent the sign of the number.
    • Magnitude or Mantissa: the number itself (123).
    • Sign of the exponent: one bit to represent the sign of the exponent (-).
    • Magnitude of the exponent: the exponent itself (3).
    • The base of the exponent: the base of the exponent (10).
    • Location of the decimal point: the location of the decimal point (3).

5 LEcture 5: Variables Binding and Scope

  • Names :
    • Names are handles to an entity within the program, such as a variable, a function, a class, a module, or a package…etc.
    • Names are denoted by identifiers.
    • Identifies usually allow letters, digits, and underscores.
  • Lifetime: the period of time during which the entity exists in memory.
  • Scope: the portion of the program where the name binding is valid.
  • L-value: the left side of an assignment statement. Usually an address in memory.
  • R-value: the right side of an assignment statement, usually the exact value of the variable.
  • Binding:
    • Binding is the association of a name with an entity, it means the name is becoming known to the compiler; and the entity is being created/allocated/instantiated/assigned…etc.
    • Binding can happen during:
      • Compile or Translation Time: Before the program is executed.
      • Load Time: During the loading of the program into memory.
      • Run Time: During the execution of the program.
    • Static Binding: The binding is permanent during the lifetime of the program. Example: A global variable. Lifetime: the program. Scope: the program.
    • Dynamic Binding: The binding is temporary during part of the lifetime of the program. Example: A local variable. Lifetime: the function call (part of the program lifetime). Scope: the function.
  • Variables:
    • A variable in imperative languages is **six-tuple**of: <name, address(location), value, type, lifetime, scope>.
    • Each property in the tuple is bound (assigned a value) at a different time.
    • The name is bound at compile time.
    • The address (l-value) is bound at load time/runtime, or runtime only depending on the language.
    • The type is bound at compile time or runtime depending on the language.
    • The value (r-value) is bound at load time (for global constants) or runtime.
    • The lifetime is bound at compile time.
    • The scope is bound at compile time.
  • Dynamic Variables:
    • The allocation of memory for dynamic variables is done at runtime (after the program has started).
    • Two types of Dynamic allocations:
      • Explicit: The programmer must explicitly allocate and deallocate memory for the variable. Example: C++ new and delete operators, C malloc() and free() functions.
      • Implicit: The language automatically allocates (when the execution is within the scope of the variable) and deallocates (when variable leaves the executions scope) memory for the variable. Example: Java, Python, C#.

10 Binding

  • Binding Time: The time at which the binding is done, which is:
  • Dynamic Binding: at execution time using assignment statements or parameter passing.
  • Static Binding: at:
    • Translation time: during compilation or interpretation or loading. e.g. Global variables (at load time).
    • Language Implementation: during the implementation of the language. e.g. bind values to representation, bind operations to machine code.
    • Language Definition: during the definition of the language. e.g. Language structures, built-in types and notation for values.
  • Binding Examples:
    • Bind + to the addition operation: happens at language definition, implementation.
    • Bind 1+3: happens at translation time, as both 1 and 3 are constants.
    • Bind x+1: happens at runtime, as x is a variable, and its value is not known until runtime.
  • Binding Keyword vs binding Reserved word:
    • Both happen at language definition.
    • Reserved words are keywords that cannot be used as identifiers.
    • Reserved words can not be redefined, while keywords can be redefined.
  • More Early binding means more Efficient code, but less Flexibility (Late binding means more Flexibility but less Efficient code).
  • Early binding is done at compile time or load time. While late binding is done at runtime.
  • Recursion is an example of late binding, as the function is called within itself, and the function is not known until runtime.

Binding Storage

  • Bindings are stored at compile time or during execution.
  • At compilation: Declarations are stored in symbol tables that maps names to attributes.
  • At Execution:
    • Runtime: maps names to memory addresses.
    • Contents: maps memory addresses to values.

Variables

  • Dereferencing: obtaining value of variable 10.
  • Aliasing:
    • Changing the name bound to a variable, using call by reference.
    • A new name is bound to the same memory location and value.
    • It is different from copying the value of a variable to another variable (call by value) where a new name is bound to a new memory location and value (equals to the original value).

Scope

  • Static Scoping:
    • Determines the scope of the variable at compile time by analyzing the program structure (lexical structure, aka. source code blockings).
    • Symbol tables are used to store the scope of variables as they are Stacks when entering a new scope, push new declarations. As soon as program is exiting a scope, pop old declarations.
  • Dynamic Scoping:
    • Symbol tables are built at runtime, push/pop declarations as the program is executing.
    • Usually associated with dynamic typing.
    • LISP, APL are examples of languages that use dynamic scoping.

Lifetime

  • Static lifetime allocation:
    • The memory is allocated at compile time.
    • When a function returns, the memory is not deallocated, that is the values from previous function calls are still in memory.
    • Example: Fortran.
  • dynamic lifetime allocation:
    • When a function returns, the memory is deallocated, all local variables are removed from memory, and when the same function get called again it will allocate new memory for the local variables (fresh).
    • Example: C.
    • use Activation Records to store the local variables of a function call.
  • Activation Records:
    • It stores the local variables and parameters of a function call.
    • It is stored in the Stack and is pushed when a function is called and popped when the function returns.
    • A procedure may have more than one activation record in the stack, if it is called recursively.

6 Elementary Data Types

Integer

  • The 2’s complement is used to represent negative integers.
  • To get the negative representation of a number, we flip all the bits (get the 1’s complement) and add 1.
  • Example:
    • 1 in binary is 00000001, the 1’s complement is 11111110, and the 2’s complement is 11111111. So -1 in binary is 11111111.
    • 127 in binary is 01111111, the 1’s complement is 10000000, and the 2’s complement is 10000001. So -127 in binary is 10000001.
  • A negative value is always represented by the leftmost bit being 1.
  • While the 1’s complement is used to represent negative integers; the 2’s complement is the most used to represent negative integers.
  • Division of two integers returns only the quotient, while modulo returns only the remainder such that a/b can be represented as a = q*b + r where q is the quotient and r is the remainder or a = b*(a/b) + (a%b).

Enumeration (Enum)

  • In C: typedef enum {Off, Low, Medium, High} Heat;, but you can still use any integer value for the enumeration. Heat h = 5; is valid, although it is not one of the enumeration values.
  • In Ada: type Heat is (Off, Low, Medium, High);, and you can’t use any integer value for the enumeration. Heat h = 5; is invalid and will cause a compilation error.
  • C++ throws a warning if you use an integer value that is not one of the enumeration values, but you can still work around it by casting the integer to the enumeration type.
  • In Effel, the enums are not supported, as they kept the language simple and easy to use, you can achieve the same functionality using your own logic and assertions.

Character

  • In Ada:
    • Character is an enumeration of all the characters in the ASCII table (256 characters).
    • To use the 16-bit Unicode character set, you need to use the Wide_Character type.
  • In C:
    • Character is an integer type that can hold values from 0 to 255.
    • Which means that 'A' + 10 is a valid expression, and it will return the value of 'A' in the ASCII table plus 10 which is 65 + 10 = 75 (10 letters after A) that is 'K'.
    • To use the 16-bit Unicode character set, you need to use the wchar_t type.

Boolean

  • In Ada:
    • Boolean is an enumeration of True and False.
    • True is represented by 1 and False is represented by 0.
  • In C:
    • Boolean is an integer type that can hold values from 0 to 255.
    • 0 is False and any other value is True.
    • bool b; b = b + 1; is valid, and b will be True after the assignment (source of bugs).

Subtype

  • A Subtype is a subset of the values of a type, and it is used to restrict the values of a type to a specific range (of integers for example).
  • Example: Temperature is a subtype of Integer that is restricted to the range of 0 to 100, although it is valid (from computer perspective) to set 101 for temperature, it does not make sense.
  • The Type of the subtype is determined at compile time, while if the value lies within the range of the subtype is determined at runtime.
  • The subtype is NOT a distinct type, but it has the same type as the parent type with a restricted range of values.

Derived Types

  • A Derived Type can be derived from a parent type and inherits all the properties of the parent type; but both types are two distinct types. You can still convert between the two types, but you need to do it explicitly.
  • Example: in ADA:
    • type Altitude is Integer range 0..1000;, Altitude is a derived type from Integer and it is restricted to the range of 0 to 1000.
    • Altitude is a distinct type from Integer, and you can’t assign an Altitude value to an Integer variable without explicitly converting it using Altitude(10) for example.
  • Both Subtypes and Derived Types are used to restrict the values of a type to a specific range, but Derived Types are preferable as they are safer and portable, and their drawback is that they need manual conversion between the parent type and the derived type. But the Subtypes are not portable and they are not distinct types, but they are easier to use as they don’t need manual conversion.

Expressions

  • Expressions can be literal or variable, or complex.
  • Literal expressions are the values themselves, like 5 or 'A'.
  • Variable expressions are expressions that contain variables need to be evaluated, like a + b.
  • Complex expressions involve operators, system or user-defined functions, and/or combinations of the above, like a + b * sin(c).
  • Expressions are evaluated to produce a value.
  • The value of a variable is the content of the memory cell denoted by the variable.
  • Passing parameters to expressions:
    • Prefix notation is used to denote function calls, like sin(x), x is passed as a parameter to the sin function.
    • Infix notation is used to denote operators, like a + b, a and b are passed as parameters to the + operator.
  • The precedence of operators is determined by the language, and it can be overridden using parentheses.
  • The associativity of operators is determined by the language, and it can be overridden using parentheses.
  • Precedence and associativity are used to determine the order of evaluation of expressions, and should never left to the compiler to decide; it should be explicitly defined by the programmer.
  • Constant Folding is the process of evaluating constant expressions at compile time, and it is used to improve the performance of the program. Example: 5 + 3 is evaluated at compile time to 8, and the compiler will replace 5 + 3 with 8 in the code and no evaluation will be done at runtime.
  • Reverse Polish Notation (RPN) is a notation that does not use parentheses, and it is used to evaluate expressions without the need for parentheses. Example: a + b * sin(c) is written as a b c sin * + in RPN. or a * (b + c) is written as a b c + * in RPN.

Assignment Statements

  • Assignment statements are used to assign values to variables as variable = expression;.
  • l-value is the left side of the assignment statement; it must be a memory location (variable), or an expression that evaluates to a memory location.
  • r-value is the right side of the assignment statement; it must be an expression that evaluates to a value, which is then stored at the memory location denoted by the l-value.
  • multiple assignments denoted by a = b = c = 5, and it is evaluated from right to left. c is assigned 5, b is assigned the value of c which is 5, and a is assigned the value of b which is 5. It can be interpreted differently in different languages, so it is better to avoid it.
  • In c, assignments are expressions, while in Ada they are statements.
  • Static values are values that are known at compile time, like 5 or 'A'.
  • Constant values are values that cant not reassigned; they can be defined at runtime, but they can’t be changed after that during their lifetime.
  • For each assignment, an instruction must be executed to copy the value from the r-value to the l-value. If the value spans more than one memory word, then multiple instructions must be executed to copy the value from the r-value to the l-value.

7 Composite Data Types

Records

  • Also known as Structures in C.
  • Records have members in C, fields in Pascal, and components in Ada.
  • Each member has a name and a type that can be any type, including another record.
typedef enum {Black, Blue, Green, Red, White} Colors;
typedef struct {
    char model[20];
    Colors color;
    int speed;
    int fuel;
} Car Data;
  • The entire record is stored in a contiguous memory area (usually), thus accessing members is very efficient as they are stored in adjacent memory locations according to their order in the record and their size.
  • If a record contains 4 members, each of size 4 bytes, then the record will be stored in a contiguous memory area of 16 bytes, the first member will be stored at address x, the second at address x + 4, the third at address x + 8, and the fourth at address x + 12.
  • If the member is a pointer, then the pointer is stored in the record, but the object it points to is stored in a different memory location, that needs to be allocated and deallocated separately.

Arrays

  • Array is a record where the members are of the same type, and they are accessed using an index.
  • The index can be an integer, or a character, or any other type that can be converted to an integer.
  • The most important function of an array is to map a logical index to a physical address, that is to map an index to a memory location (variable value).
  • Trying to modify array[index], will result in error if index is out of bounds, nad it may modify a different variable if index is out of bounds (the variable that is stored in the memory location after the array).
  • Array type checking is a powerful tool for improving the reliability of programs; however, the definition of the array bounds should not be part of the static definition of a type.
  • Array Subtypes is an index constraint applied on unconstrained array type. Example: Day[] Month is an array of 31 elements, each of type Day.

Strings

  • Strings are an array of characters.
  • In c, Strings are terminated by a null character \0, and they are stored in a contiguous memory area. When copying a string, the null character must be copied as well, otherwise the string will not be terminated and the content of the memory location after the string will be considered part of the string which corrupts the data.
  • First, strings where stored in a contiguous memory area, and the length of the string needed to be computed every time. Then, the length of the string was stored in a separate memory location, and the string was stored in a contiguous memory area, but this made the string modification more complex as the length of the string needed to be updated every time the string was modified.

Multidimensional Arrays

  • Multidimensional arrays are arrays of arrays.
  • Ada has special notation for multidimensional arrays, but it can work fine with the array of arrays notation.
  • Indexing of an array:

    • To find the the memory location of element i within an array A, we need to know the size of each element s, and the starting address of the array A as AddressOf(A[i]) = AddressOf(A) + size(element) * (i - A[First]).
    • If A[First] is 0, then AddressOf(A[i]) = AddressOf(A) + size(element) * i which optimizes the computation; this why arrays in c start at 0.
    • You can use pointers to access arrays, which is more efficient but more difficult to understand.
    typedef struct {
        //    . . .
        int field;
    } Element;
    
    int count = 100; // number of elements in the array
    Element a[count]; // initialize the array
    
    Element* ptr; // pointer to the first element of the array
    
    // loop through the array
    for (ptr=&a; ptr < &a + count * sizeof(Element); ptr += sizeof(Element)>){
        // you can access the element using *ptr
    }
    
  • Indexing of Multidimensional arrays:

    • My be inefficient.
    • Arrays are stored in a contiguous memory area, so the index of the first element of the array is enough to compute the index of any element in the array.

11 Decimals

  • Decimals are used to store numbers with a fixed number of digits after the decimal point.
  • Usually used with money, they don’t have floating point as numbers are stored as integers.
  • Decimals use more memory and have limited range, but they are more accurate, no rounding errors, no exponent, and no overflow.
  • Example: Binary Coded Decimal (BCD), each digit is stored in 4 bits, so the range is 0-9, and the number 1234 is stored as 0001 0010 0011 0100.

8 Dynamic, Static, Strong, and Weak Typing

  • Dynamic vs Static:
    • Static typing requires the programmer to define the type of variable before creating it;
    • while dynamic typing can infer the type of the variable from the value assigned to it.
  • Strong vs Weak:
    • How flexible the language is in allowing operations on different types of variables, and how it handles type errors.
    • E.g. adding a string to an integer or float to an integer.
    • Strongly typed throws on operations on different types, while weakly typed coerces the types to match.
    • Weakly typed languages allow for reassigning a variable to a different type, while strongly typed languages don’t.
    • E.g. in Python, x = 1 and x = "hello" are both valid, but in Strongly typed language, x = 1 is valid, but x = "hello" is not.
  • Static typed languages: C, C++, Java, C#, Ada, Pascal, Fortran, Cobol, and Algol.
  • Dynamic typed languages: Python, Ruby, Perl, Lisp, Scheme, Smalltalk, and JavaScript.
  • Strongly typed languages: C#, Java, Go, Python, C++, …etc.
  • Weakly typed languages: JavaScript, PHP, …etc.
  • Python is a dynamic, strongly typed language.
  • Degrees of strength or weakness vary from one language to another. C > C++ > JS.

References


  1. UoPeople. (2023). CS4402: Comparative Programming Languages. Lecture Notes Unit 3. Lecture 1: Binary And Data Encoding. 

  2. UoPeople. (2023). CS4402: Comparative Programming Languages. Lecture Notes Unit 3. Lecture 2: Elementary Data Types. 

  3. UoPeople. (2023). CS4402: Comparative Programming Languages. Lecture Notes Unit 3. Lecture 3: Composite Data Types. 

  4. UoPeople. (2023). CS4402: Comparative Programming Languages. Lecture Notes Unit 3. Lecture 4: Representing Real Numbers. 

  5. UoPeople. (2023). CS4402: Comparative Programming Languages. Lecture Notes Unit 3. Lecture 5: Variables Binding and Scope. 

  6. Ben-Ari, M. (2006). Understanding programming languages. Weizman Institute of Science. Chapter 4: Elementary Data Types. 

  7. Ben-Ari, M. (2006). Understanding programming languages. Weizman Institute of Science. Chapter 5: Composite Data Types. 

  8. Hurd, T. (2021). Introduction to Data Types: Static, Dynamic, Strong & Weak. SitePoint. https://www.sitepoint.com/typing-versus-dynamic-typing/ 

  9. Curren M. J. (1994). Little Endian vs. Big Endian. NovelTheory. https://www.noveltheory.com/TechPapers/endian.html 

  10. Lecture 6: Bindings by Benjamin J. Keller of the Department of Computer Science, Virginia Tech available at: http://courses.cs.vt.edu/~cs3304/Spring02/lectures/lect06.pdf 

  11. Lecture notes in Programming Language Theory by Nancy E. Reed of the University of Hawaii available at: https://pdfs.semanticscholar.org/ce14/aff89ec1e53c5df86cfabe607cb33af3a54d.pdf 

  12. Programming Languages Session 2 – Main Theme Imperative Languages: Names, Scoping, and Bindings by Dr. Jean-Claude Franchitti of New York University available at: http://www.nyu.edu/classes/jcf/g22.2110-001_sp11/slides/session2/ImperativeLanguages-NamesScopingAndBindings.pdf 

  13. Article that describes 2’s complement from Cornell University Available at: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html