diff --git a/concepts/number-types/.meta/config.json b/concepts/number-types/.meta/config.json new file mode 100644 index 00000000..cf56f459 --- /dev/null +++ b/concepts/number-types/.meta/config.json @@ -0,0 +1,5 @@ +{ + "blurb": "Crystal has specific number types for integers and floats. These allows you to have more control over the numbers and memory usage. Crystal has syntax for converting between these types and declaring them.", + "authors": ["meatball133"], + "contributors": ["glennj", "ihid"] +} diff --git a/concepts/number-types/about.md b/concepts/number-types/about.md new file mode 100644 index 00000000..db097989 --- /dev/null +++ b/concepts/number-types/about.md @@ -0,0 +1,109 @@ +# Number types + +Crystal has a variety of different number types for different purposes. +For example, some types are faster but have a smaller range of possible values than other types. +Some that have a larger range of possible values but are slower. + +In Crystal, there are both signed and unsigned integer types. +The signed integer types can be positive or negative. +The unsigned integer types can only be positive. + +## Signed integers types + +These are the [signed integer types][int] in Crystal: + +| Type | Size (bits) | Range | +| -------- | ----------- | ----------------------------------------------------------------------------------------------------------- | +| `Int8` | 8 | -128 to 127 | +| `Int16` | 16 | -32_768 to 32_767 | +| `Int32` | 32 | -2_147_483_648 to 2_147_483_647 | +| `Int64` | 64 | -9_223_372_036_854_775_808 to 9_223_372_036_854_775_807 | +| `Int128` | 128 | -170_141_183_460_469_231_731_687_303_715_884_105_728 to 170_141_183_460_469_231_731_687_303_715_884_105_727 | + +The smaller types use less memory and are faster than the larger types but have a smaller range of possible values. + +Where you know that values will be within a certain range, it is best to use the smallest type possible to save memory and improve performance. + +The default integer type is `Int32`. +To declare an integer with a specific type you can use the type name as a suffix, by adding `_i`. + +```crystal +1_i8.class +# => Int8 +``` + +To convert between different integer types you can use the `to_i` method. +The `to_i` method converts to the default integer type, which is `Int32`. + +```crystal +1_i8.to_i16.class +# => Int16 + +2_i16.to_i.class +# => Int32 +``` + +## Unsigned integers types + +These the [unsigned integer][uint] types in Crystal: + +`UInt8`, `UInt16`, `UInt32`, `UInt64`, `UInt128` + +The only difference to signed integers is that unsigned integers can only be positive. +To declare an unsigned integer with a specific type you can use the type name as a suffix, by adding `_u`. +To convert between different unsigned integer types you can use the `to_u` method. +The `to_u` method converts to the default unsigned integer type, which is `UInt32`. + +```crystal +1_u8.to_u16.class +# => UInt16 +``` + +## Floating point types + +These are the floating point types in Crystal: + +| Type | Size (bits) | Range | +| --------- | ----------- | -------------------- | +| `Float32` | 32 | 1.2E-38 to 3.4E+38 | +| `Float64` | 64 | 2.3E-308 to 1.7E+308 | + +There are two different [floating point types][float], one is more precise than the other. + +The default floating point type is `Float64`. + +To convert between different floating point types you can use the `to_f` method. +The `to_f` method converts to the default floating point type, which is `Float64`. + +## Type after an operation + +When you execute an operation between two numbers, the result will be of the type of the number with the highest precision. +Float is more precise than an integer and an integer is more precise than an unsigned integer. +Then `Float64` is more precise than Float32 and so on. + +```crystal +(1_u8 + 2_u64).class +# => UInt64 + +(1_u8 + 2_i64).class +# => Int64 + +(1_u8 + 2.0_f64).class +# => Float64 +``` + +## Dig Deeper: unsigned integers vs signed integers + +```exercism/advanced +Under the hood, what differentiates unsigned and signed integers is that signed integers use the first bit to store the sign. +The sign is either positive or negative. +For unsigned integers, the first bit is used to store the value. +So for a signed 32-bit integer is the max value 2^31 - 1. +For an unsigned 32-bit integer is the max value 2^32 - 1. + +If you are interested in learning more about signedness you can read more about it on [Wikipedia](https://en.wikipedia.org/wiki/Signedness). +``` + +[float]: https://crystal-lang.org/api/latest/Float.html +[int]: https://crystal-lang.org/api/latest/Int.html +[uint]: https://crystal-lang.org/api/latest/UInt32.html diff --git a/concepts/number-types/introduction.md b/concepts/number-types/introduction.md new file mode 100644 index 00000000..1360fe7d --- /dev/null +++ b/concepts/number-types/introduction.md @@ -0,0 +1,80 @@ +# Number types + +Crystal has a variety of different number types for different purposes. +For example, some types are faster but have a smaller range of possible values than other types. +Some that have a larger range of possible values but are slower. + +In Crystal, there are both signed and unsigned integer types. +The signed integer types can be positive or negative. +The unsigned integer types can only be positive. + +## Signed integers types + +These are the [signed integer types][int] in Crystal: + +| Type | Size (bits) | Range | +| -------- | ----------- | ----------------------------------------------------------------------------------------------------------- | +| `Int8` | 8 | -128 to 127 | +| `Int16` | 16 | -32_768 to 32_767 | +| `Int32` | 32 | -2_147_483_648 to 2_147_483_647 | +| `Int64` | 64 | -9_223_372_036_854_775_808 to 9_223_372_036_854_775_807 | +| `Int128` | 128 | -170_141_183_460_469_231_731_687_303_715_884_105_728 to 170_141_183_460_469_231_731_687_303_715_884_105_727 | + +The smaller types use less memory and are faster than the larger types but have a smaller range of possible values. + +Where you know that values will be within a certain range, it is best to use the smallest type possible to save memory and improve performance. + +The default integer type is `Int32`. +To declare an integer with a specific type you can use the type name as a suffix, by adding `_i`. + +```crystal +1_i8.class +# => Int8 +``` + +To convert between different integer types you can use the `to_i` method. +The `to_i` method converts to the default integer type, which is `Int32`. + +```crystal +1_i8.to_i16.class +# => Int16 + +2_i16.to_i.class +# => Int32 +``` + +## Unsigned integers types + +These the [unsigned integer][uint] types in Crystal: + +`UInt8`, `UInt16`, `UInt32`, `UInt64`, `UInt128` + +The only difference to signed integers is that unsigned integers can only be positive. +To declare an unsigned integer with a specific type you can use the type name as a suffix, by adding `_u`. +To convert between different unsigned integer types you can use the `to_u` method. +The `to_u` method converts to the default unsigned integer type, which is `UInt32`. + +```crystal +1_u8.to_u16.class +# => UInt16 +``` + +## Floating point types + +These are the floating point types in Crystal: + +| Type | Size (bits) | Range | +| --------- | ----------- | -------------------- | +| `Float32` | 32 | 1.2E-38 to 3.4E+38 | +| `Float64` | 64 | 2.3E-308 to 1.7E+308 | + +There are two different [floating point types][float], one is more precise than the other. + +The default floating point type is `Float64`. + +To convert between different floating point types you can use the `to_f` method. +The `to_f` method converts to the default floating point type, which is `Float64`. + +[float]: https://crystal-lang.org/api/latest/Float.html +[int]: https://crystal-lang.org/api/latest/Int.html +[uint]: https://crystal-lang.org/api/latest/UInt32.html diff --git a/concepts/number-types/links.json b/concepts/number-types/links.json new file mode 100644 index 00000000..031d22e7 --- /dev/null +++ b/concepts/number-types/links.json @@ -0,0 +1,14 @@ +[ + { + "url": "https://en.wikipedia.org/wiki/Signedness", + "description": "Wikipedia: Signedness" + }, + { + "url": "https://crystal-lang.org/reference/latest/syntax_and_semantics/literals/floats.html", + "description": "Crystal docs: Float" + }, + { + "url": "https://crystal-lang.org/reference/latest/syntax_and_semantics/literals/integers.html", + "description": "Crystal docs: Int" + } +] diff --git a/config.json b/config.json index ca297301..3c320715 100644 --- a/config.json +++ b/config.json @@ -56,6 +56,14 @@ ], "status": "wip" }, + { + "slug": "navigation-computer", + "name": "Navigation Computer", + "uuid": "d980412c-1480-453a-be6c-2cd7779284bc", + "concepts": ["number-types"], + "prerequisites": ["numbers"], + "status": "wip" + }, { "slug": "wellingtons-weather-station", "name": "Wellington's Weather Station", @@ -919,6 +927,11 @@ "slug": "bools", "name": "Bools" }, + { + "uuid": "43dd66b4-5d26-44b6-8f2e-2a0392c642b2", + "slug": "number-types", + "name": "Number Types" + }, { "uuid": "4aa0a83d-393a-412e-8175-65bbf7fcd8d6", "slug": "numbers", diff --git a/exercises/concept/navigation-computer/.docs/hints.md b/exercises/concept/navigation-computer/.docs/hints.md new file mode 100644 index 00000000..77970440 --- /dev/null +++ b/exercises/concept/navigation-computer/.docs/hints.md @@ -0,0 +1,24 @@ +# Hints + +## General + +- Declaring a numeral with a specific type is done by appending the type to the numeral, e.g. `42_u8` for an unsigned 8-bit integer. +- Converting between different types is done by calling the `to_` method on the numeral, e.g. `42u8.to_u16` for an unsigned 16-bit integer. + +## 1. Navigation constants + +- You need to define [constants][constants] that should contain a [integer][integers]. +- The constant should be declared inside the `Navigation` class. +- The constant needs to be declared outside of any method. + +## 2. Correct area analysis + +- You need to convert the input to an unsigned integer. + +## 3. Calculate the velocity + +- To get the velocity you need to divide the distance by the time. +- The result of a numeric operation will be of the highest precision type, so you need to convert the result to the correct type. + +[constants]: https://crystal-lang.org/reference/syntax_and_semantics/constants.html +[integers]: https://crystal-lang.org/reference/latest/syntax_and_semantics/literals/integers.html diff --git a/exercises/concept/navigation-computer/.docs/instructions.md b/exercises/concept/navigation-computer/.docs/instructions.md new file mode 100644 index 00000000..bd0d4762 --- /dev/null +++ b/exercises/concept/navigation-computer/.docs/instructions.md @@ -0,0 +1,65 @@ +# Instructions + +The ESA (Exercism Space Agency) is at full speed in planning a new mission to [Phobos][phobos], a moon of Mars. +The mission's goal is to land a probe on the surface of Phobos and to send back data about the surface. +ESA has requested your help to build the navigation computer for the probe. +The navigation computer has limited memory so we need to keep the memory usage as low as possible. +Thereby we need to use the right data types. + +## 1. Navigation constants + +The navigation computer needs to know the distance between some objects in space to do the right calculations, the distance is measured in km. + +Define the following constants: + +- `NEPTUNE_DISTANCE` with the value `4_400_000_000` which should be stored as a `Int64` +- `MARS_DISTANCE` with the value `227_940_000` which should be stored as a `Int32` +- `ATMOSPHERE_DISTANCE` with the value `10_000` which should be stored as a `Int16` + +## 2. Correct area analysis + +The navigation computer needs to know the area of some objects in space to do the right calculations. +An area can **NOT** be negative. +The engineers had the plan that the program would generate an overflow error when the area is negative. +But the engineers forgot to change the signed integer to an unsigned integer. + +Thereby the engineers would like a program that converts the signed integer to an unsigned integer. + +Implement the `Navigation#correct_area_analysis` method that takes a `measurement` as an argument and returns the area as an unsigned integer with 32 bits. + +```crystal +measurement = 52554 +measurement.class +# => Int32 + +Navigation.new.correct_area_analysis(measurement) +# => 52554 + +Navigation.new.correct_area_analysis(measurement).class +# => UInt32 +``` + +## 3. Calculate the velocity + +The navigation computer needs to know the velocity of the probe. +The velocity is measured in m/s. + +To get the velocity we need to know the distance and the time it took to travel that distance. +Then take the distance and divide it by the time. + +The velocity doesn't have to be super accurate and will never be a big number, therefore we can use a `Float32`. + +Implement the `Navigation#calculate_velocity` method that takes `distance` and `time` as arguments and returns the velocity as a `Float` with 32 bits. + +```crystal +distance = 52554 +time = 2.5 + +Navigation.new.calculate_velocity(distance, time) +# => 21021.6 + +Navigation.new.calculate_velocity(distance, time).class +# => Float32 +``` + +[phobos]: https://en.wikipedia.org/wiki/Phobos_(moon) diff --git a/exercises/concept/navigation-computer/.docs/introduction.md b/exercises/concept/navigation-computer/.docs/introduction.md new file mode 100644 index 00000000..1360fe7d --- /dev/null +++ b/exercises/concept/navigation-computer/.docs/introduction.md @@ -0,0 +1,80 @@ +# Number types + +Crystal has a variety of different number types for different purposes. +For example, some types are faster but have a smaller range of possible values than other types. +Some that have a larger range of possible values but are slower. + +In Crystal, there are both signed and unsigned integer types. +The signed integer types can be positive or negative. +The unsigned integer types can only be positive. + +## Signed integers types + +These are the [signed integer types][int] in Crystal: + +| Type | Size (bits) | Range | +| -------- | ----------- | ----------------------------------------------------------------------------------------------------------- | +| `Int8` | 8 | -128 to 127 | +| `Int16` | 16 | -32_768 to 32_767 | +| `Int32` | 32 | -2_147_483_648 to 2_147_483_647 | +| `Int64` | 64 | -9_223_372_036_854_775_808 to 9_223_372_036_854_775_807 | +| `Int128` | 128 | -170_141_183_460_469_231_731_687_303_715_884_105_728 to 170_141_183_460_469_231_731_687_303_715_884_105_727 | + +The smaller types use less memory and are faster than the larger types but have a smaller range of possible values. + +Where you know that values will be within a certain range, it is best to use the smallest type possible to save memory and improve performance. + +The default integer type is `Int32`. +To declare an integer with a specific type you can use the type name as a suffix, by adding `_i`. + +```crystal +1_i8.class +# => Int8 +``` + +To convert between different integer types you can use the `to_i` method. +The `to_i` method converts to the default integer type, which is `Int32`. + +```crystal +1_i8.to_i16.class +# => Int16 + +2_i16.to_i.class +# => Int32 +``` + +## Unsigned integers types + +These the [unsigned integer][uint] types in Crystal: + +`UInt8`, `UInt16`, `UInt32`, `UInt64`, `UInt128` + +The only difference to signed integers is that unsigned integers can only be positive. +To declare an unsigned integer with a specific type you can use the type name as a suffix, by adding `_u`. +To convert between different unsigned integer types you can use the `to_u` method. +The `to_u` method converts to the default unsigned integer type, which is `UInt32`. + +```crystal +1_u8.to_u16.class +# => UInt16 +``` + +## Floating point types + +These are the floating point types in Crystal: + +| Type | Size (bits) | Range | +| --------- | ----------- | -------------------- | +| `Float32` | 32 | 1.2E-38 to 3.4E+38 | +| `Float64` | 64 | 2.3E-308 to 1.7E+308 | + +There are two different [floating point types][float], one is more precise than the other. + +The default floating point type is `Float64`. + +To convert between different floating point types you can use the `to_f` method. +The `to_f` method converts to the default floating point type, which is `Float64`. + +[float]: https://crystal-lang.org/api/latest/Float.html +[int]: https://crystal-lang.org/api/latest/Int.html +[uint]: https://crystal-lang.org/api/latest/UInt32.html diff --git a/exercises/concept/navigation-computer/.meta/config.json b/exercises/concept/navigation-computer/.meta/config.json new file mode 100644 index 00000000..c74b9a81 --- /dev/null +++ b/exercises/concept/navigation-computer/.meta/config.json @@ -0,0 +1,11 @@ +{ + "authors": ["meatball133"], + "contributors": ["ihid", "glennj"], + "files": { + "solution": ["src/navigation_computer.cr"], + "test": ["spec/navigation_computer_spec.cr"], + "exemplar": [".meta/src/exemplar.cr"] + }, + "icon": "land-grab-in-space", + "blurb": "Learn about number types while building a navigation system for ESA (Exercism Space Agency)." +} diff --git a/exercises/concept/navigation-computer/.meta/design.md b/exercises/concept/navigation-computer/.meta/design.md new file mode 100644 index 00000000..b4cbbca4 --- /dev/null +++ b/exercises/concept/navigation-computer/.meta/design.md @@ -0,0 +1,30 @@ +## Goal + +The goal of this exercise is to teach the student about numbers types in Crystal. + +## Learning objectives + +- Know that there is multiple number types for `Int`, `UInt` and `Float` +- Know how to declare a number with a specific type +- Know how to convert between specific number types +- Know how operations between different number types work + +## Out of scope + +- `BigInt` and `BigFloat` + +## Concepts + +`Number-types`: + +- UInt and its type +- Int and its type +- Float and its type +- How to convert between specific number types +- Know that there is a default number type +- Know how to declare a number with a specific type +- Know the hierarchy of number types when doing operations. + +## Prerequisites + +- Number diff --git a/exercises/concept/navigation-computer/.meta/src/exemplar.cr b/exercises/concept/navigation-computer/.meta/src/exemplar.cr new file mode 100644 index 00000000..8489d306 --- /dev/null +++ b/exercises/concept/navigation-computer/.meta/src/exemplar.cr @@ -0,0 +1,13 @@ +class Navigation + NEPTUNE_DISTANCE = 4_400_000_000_i64 + MARS_DISTANCE = 227_940_000_i32 + ATMOSPHERE_DISTANCE = 10_000_i16 + + def correct_area_analysis(messurment) + messurment.to_u + end + + def calculate_velocity(distance, time) + (distance / time).to_f32 + end +end diff --git a/exercises/concept/navigation-computer/spec/navigation_computer_spec.cr b/exercises/concept/navigation-computer/spec/navigation_computer_spec.cr new file mode 100644 index 00000000..d1a6e14e --- /dev/null +++ b/exercises/concept/navigation-computer/spec/navigation_computer_spec.cr @@ -0,0 +1,57 @@ +require "spec" +require "../src/*" + +describe "Navigation" do + describe "Constants" do + it "NEPTUNE_DISTANCE should be 4.4 billion km and be int64" do + distance = Navigation::NEPTUNE_DISTANCE + distance.should eq 4_400_000_000 + distance.should be_a(Int64) + end + + it "MARS_DISTANCE should be 227_940_000 km and be int32" do + distance = Navigation::MARS_DISTANCE + distance.should eq 227_940_000 + distance.should be_a(Int32) + end + it "ATMOSPHERE_DISTANCE should be 10_000 km and be int16" do + distance = Navigation::ATMOSPHERE_DISTANCE + distance.should eq 10_000 + distance.should be_a(Int16) + end + end + + describe "correct_area_analysis" do + it "Giving 9999 should return 9999 as Uint" do + result = Navigation.new.correct_area_analysis(9_999) + result.should eq 9_999 + result.should be_a(UInt32) + end + + it "Giving 0 should return 0 as Uint" do + result = Navigation.new.correct_area_analysis(0) + result.should eq 0 + result.should be_a(UInt32) + end + end + + describe "calculate_velocity" do + it "1000 m and 5 seconds should equal 200 meter per second" do + calculation = Navigation.new.calculate_velocity(1000, 5) + calculation.should eq 200 + calculation.should be_a(Float32) + end + + it "502.5 m and 2.5 seconds should equal 201 meter per second" do + calculation = Navigation.new.calculate_velocity(502.5, 2.5) + calculation.should eq 201 + calculation.should be_a(Float32) + end + + it "4531 m and 14.6 seconds should equal 310.34247 meter per second" do + calculation = Navigation.new.calculate_velocity(4531, 14.6) + calculation.should eq 310.34247_f32 + calculation.should be_a(Float32) + end + end +end diff --git a/exercises/concept/navigation-computer/src/navigation_computer.cr b/exercises/concept/navigation-computer/src/navigation_computer.cr new file mode 100644 index 00000000..967ab90f --- /dev/null +++ b/exercises/concept/navigation-computer/src/navigation_computer.cr @@ -0,0 +1,13 @@ +class Navigation + # TODO: define the 'NEPTUNE_DISTANCE' constant + # TODO: define the 'MARS_DISTANCE' constant + # TODO: define the 'ATMOSPHERE_DISTANCE' constant + + def correct_area_analysis(messurment) + raise "Please implement the Navigation#correct_area_analysis method" + end + + def calculate_velocity(distance, time) + raise "Please implement the Navigation#calculate_velocity method" + end +end