# How to work with atoms

_This page introduces the atom types in q and highlights the behavior that is specific to q._

An atom is an irreducible value of a specific data type. The basic data types in q correspond mostly to those of traditional programming languages, with additional date- and time-related types that facilitate time series.

This is not a comprehensive guide to atoms. It focuses on the features specific to q. Refer to _Q for Mortals_ [§2. Basic Data Types – Atoms](../../../learn/q4m/2_Basic_Data_Types_Atoms.md) for a comprehensive guide and to the [datatypes reference card](../../../ref/datatypes.md) for a quick reference page.

Every atom has a negative [type](../../../ref/type.md) number. The corresponding [list](lists.md) type is the same number, positive:
```q
q)type 42       / long atom
-7h
q)type 42 43    / long list
7h
```

The following table summarizes the atom types. Each has a literal form, and most have a dedicated null and infinity literal:

| Type | Size (bytes) | Example literal | Null | Infinity |
| ---- | ----: | ---- | ---- | ---- |
| `boolean` | 1 | `1b` | | |
| `guid` | 16 | | `0Ng` | |
| `byte` | 1 | `0x2a` | | |
| `short` | 2 | `42h` | `0Nh` | `0Wh` |
| `int` | 4 | `42i` | `0Ni` | `0Wi` |
| `long` | 8 | `42` | `0N` | `0W` |
| `real` | 4 | `3.14e` | `0Ne` | `0We` |
| `float` | 8 | `3.14` | `0n` | `0w` |
| `char` | 1 | `"a"` | `" "` | |
| `symbol` | | `` `abc `` | `` ` `` | |
| `timestamp` | 8 | `2026.09.10D14:30:00.000000000` | `0Np` | `0Wp` |
| `month` | 4 | `2026.09m` | `0Nm` | `0Wm` |
| `date` | 4 | `2026.09.10` | `0Nd` | `0Wd` |
| `timespan` | 8 | `0D14:30:00.000000000` | `0Nn` | `0Wn` |
| `minute` | 4 | `14:30` | `0Nu` | `0Wu` |
| `second` | 4 | `14:30:00` | `0Nv` | `0Wv` |
| `time` | 4 | `14:30:00.000` | `0Nt` | `0Wt` |

## Boolean

Booleans are one byte each. Write them with a `b` suffix, and write a boolean list as a run of digits followed by `b`:
```q
q)type 1b
-1h
q)0101b     / boolean list, no separators needed
0101b
```

Booleans behave as 0 and 1 in arithmetic. q promotes them to `int`, not `long`:


**q**
```q
q)1b + 1b
2i
q)sum 1011b
3i
```


**Python**
```python
>>> True + True
2
>>> sum([True, False, True, True])
3
```


Logical `and` and `or` are the [`&`](../../../ref/lesser.md) (lesser) and [`|`](../../../ref/greater.md) (greater) operators, which is why they generalize to non-boolean types. The keywords `and` and `or` are synonyms. Use [`any`](../../../ref/all-any.md) and [`all`](../../../ref/all-any.md) to aggregate:
```q
q)1b & 0b
0b
q)0b | 1b
1b
q)not 1b
0b
q)(any; all) @\: 0011b
10b
```

Casting to `boolean` maps zero to `0b` and everything else to `1b`:
```q
q)`boolean$0 1 2
011b
q)"b"$1
1b
```

## Byte

A byte is written with the `0x` prefix. Bytes are the raw building block of serialization and bit manipulation:
```q
q)type 0x2a
-4h
q)"x"$42
0x2a
```

Use [`vs`](../../../ref/vs.md) to split a value into its byte or bit representation:
```q
q)0x0 vs 42i    / byte representation of an int
0x0000002a
q)0b vs 0x2a    / bit representation of a byte
00101010b
```

> **Note — Byte has no null and no infinity**
>
>
> Every byte pattern is a valid value, so there is nothing left over to reserve for a null. Consequently [`null`](../../../ref/null.md) never returns `1b` for a byte, and byte columns cannot represent _missing_.
>
> ```q
> q)null 0x00
> 0b
> ```
>
## Integers (short, int, long)

q has three signed integer widths: `short` (2 bytes), `int` (4 bytes), and `long` (8 bytes). **`long` is the default**, so an integer literal without a suffix is a `long`:
```q
q)type 42
-7h
q)type 42i
-6h
q)type 42h
-5h
```

> **Note — There are no unsigned integers in q**
>
>
> If you need to interpret unsigned data, either read it as a byte vector or widen it to the next larger signed type. There is also no dedicated 128-bit type.
>
q promotes arithmetic on `short` and `int` to `int`; only `long` arithmetic stays `long`:
```q
q)type 42h + 42h
-6h
q)type 42i + 42i
-6h
```

There is **no overflow detection**. Exceeding the range of a type silently wraps, which can land exactly on the null value:
```q
q)2147483647i + 1i
0Ni
```

Division with [`%`](../../../ref/divide.md) always returns a float, regardless of the operand types. For integer division and remainder use [`div`](../../../ref/div.md) and [`mod`](../../../ref/mod.md), which round toward negative infinity:


**q**
```q
q)type 7 % 2   / always float
-9h
q)7 div 2
3
q)7 mod 2
1
q)-7 div 2     / floor, not truncation
-4
q)-7 mod 2
1
```


**Python**
```python
>>> type(7 / 2)
<class 'float'>
>>> 7 // 2
3
>>> 7 % 2
1
>>> -7 // 2
-4
>>> -7 % 2
1
```


## Floating point (real, float)

`float` (8 bytes) is the default; `real` (4 bytes) is written with an `e` suffix:
```q
q)type 3.14
-9h
q)type 3.14e
-8h
```

It is useful to understand the precision of a floating-point number. By default, the console shows seven significant digits, which hides the stored value. Use the [`\P`](../../../ref/syscmds.md#p-precision) system command to see everything:
```q
q)1 % 3
0.3333333
q)\P 0
q)1 % 3
0.33333333333333331
q)0.1 + 0.2
0.30000000000000004
q)\P 7                  / restore the default display precision
```

Comparing floating-point numbers might surprise you. The [`=`](../../../ref/comparison.md) operator implements _tolerant_ equality: two floats compare equal if their difference is small relative to their magnitude. Test for exact equality with `0 = x - y`:
```q
q)(0.1 + 0.2) = 0.3       / tolerant equality
1b
q)0 = 0.3 - (0.1 + 0.2)   / exact equality
0b
```

More about [float precision](../../../ref/precision.md).

### Formatting a number for display

`\P` changes the console display globally. To format an individual value instead, two utilities return the number as a string:
```q
q).Q.f[2; 3.14159]        / 2 decimal places
"3.14"
q).Q.fmt[8; 2; 3.14159]   / 2 decimal places, padded to a width of 8
"    3.14"
```

`.Q.fmt` pads to a fixed width, which is what you want for aligning a column of numbers.

See [`.Q.f`](../../../ref/dotq.md#f-precision-format) and [`.Q.fmt`](../../../ref/dotq.md#fmt-precision-format).

## Text data: characters, strings, and symbols

q has two text types, and the distinction matters:

- `char` (`"a"`) is an atom of one character. A _string_ is a **list** of chars — there is no string atom.
- `symbol` (`` `abc ``) is the atomic text type: however long the name, a symbol is a single, indivisible value.
```q
q)type "a"      / char atom
-10h
q)type "abc"    / char list, that is, a string
10h
q)type `abc     / symbol atom
-11h
q)count "abc"
3
q)count `abc    / a symbol is an atom
1
```

Symbols are interned: each distinct symbol is stored once in a global pool and referenced by an index. Comparison is then an integer comparison rather than a character-by-character walk, and storage is constant per value, so symbols are the natural choice for repeated, low-cardinality values such as instrument names. They are also the basis of [enumerations](../../../ref/enumerations.md). The cost is that the pool never shrinks during a session, so avoid creating symbols out of unbounded, high-cardinality data.

A symbol never matches a string, and comparing the two raises an error:
```q
q)`abc ~ "abc"
0b
q)`abc = "abc"
'type
  [0]  `abc = "abc"
            ^
```

Convert between the two with [`string`](../../../ref/string.md) and [`$`](../../../ref/cast.md). Use `` `$ `` for symbols whose names cannot otherwise be written:
```q
q)string `abc
"abc"
q)`$"abc"
`abc
q)`$"hello world"   / symbols can contain spaces
`hello world
```

### Pattern matching with `like`

Use [`like`](../../../ref/like.md) to match text against a pattern. It accepts `*` (any sequence), `?` (any single character), and `[]` (character class), and it iterates over a symbol list:
```q
q)"Alice" like "A*"
1b
q)"Alice" like "?lice"
1b
q)"Alice" like "[AB]lice"
1b
q)"Alice" like "a*"                 / case sensitive
0b
q)`Alice`Bob`Charlie like "*e"      / iterates over a symbol list
101b
```

For substring search and replacement, use [`ss` and `ssr`](../../../ref/ss.md), and for case conversion [`lower` and `upper`](../../../ref/lower.md):


**q**
```q
q)ssr["hello world"; "world"; "q"]
"hello q"
q)upper "alice"
"ALICE"
q)lower `ALICE     / also applies to symbols
`alice
```


**Python**
```python
>>> "hello world".replace("world", "q")
'hello q'
>>> "alice".upper()
'ALICE'
```


### Character constants

The [`.Q` namespace](../../../ref/dotq.md) provides ready-made character vectors that save you typing character ranges:
```q
q).Q.A       / uppercase alphabet
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
q).Q.a       / lowercase alphabet
"abcdefghijklmnopqrstuvwxyz"
q).Q.an      / all alphanumerics, including underscore
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"
```

See [`.Q.A`](../../../ref/dotq.md#a-upper-case-alphabet), [`.Q.a`](../../../ref/dotq.md#a-lower-case-alphabet), and [`.Q.an`](../../../ref/dotq.md#an-all-alphanumerics).

## Temporal values

Rich temporal support is what makes q a time-series language. The primary types are `timestamp`, `date`, `timespan`, and `time`, with nanosecond precision available where it matters:
```q
q)type 2026.09.10                           / date
-14h
q)type 2026.09.10D14:30:00.123456789        / timestamp, nanosecond precision
-12h
q)type 0D14:30:00.000000000                 / timespan, nanosecond precision
-16h
q)type 14:30:00.000                         / time, millisecond precision
-19h
```

Also available are coarser types, useful as bucketing keys: `month`, `minute`, and `second`:
```q
q)type 2026.09m     / month
-13h
q)type 14:30        / minute
-17h
q)type 14:30:00     / second
-18h
```

Temporal values are encoded as integers counting from the epoch `2000.01.01`, so arithmetic works as you expect and casting to an integer exposes the underlying count:


**q**
```q
q)2026.09.10 + 1                        / next day
2026.09.11

q)2026.09.10 - 2026.09.01               / difference in days
9i
q)"j"$2026.09.10                        / days since the epoch
9749
q)"j"$2026.09.10D00:00:00.000000001     / one nanosecond past midnight
842313600000000001
q)2026.09.10D14:30:00 + 0D01:00:00      / add a duration
2026.09.10D15:30:00.000000000
```


**Python**
```python
>>> from datetime import date, datetime, timedelta
>>> date(2026, 9, 10) + timedelta(days=1)
datetime.date(2026, 9, 11)
>>> date(2026, 9, 10) - date(2026, 9, 1)
datetime.timedelta(days=9)
>>> (date(2026, 9, 10) - date(2000, 1, 1)).days
9749
>>> datetime(2026, 9, 10) + timedelta(microseconds=0.001)
datetime.datetime(2026, 9, 10, 0, 0)
>>> datetime(2026, 9, 10, 14, 30) + timedelta(hours=1)
datetime.datetime(2026, 9, 10, 15, 30)
```


Two differences are worth dwelling on. Temporal arithmetic in q needs no wrapper type: a date plus an integer is a date, and a difference is a plain number you can aggregate. The nanosecond example is also not a like-for-like comparison. q addresses a single nanosecond directly, whereas the standard library's `datetime` resolves only to microseconds and discards the nanosecond without complaint.

Adding a date and a time yields a timestamp, and adding a date and a timespan does the same — which is what the `D` in a timestamp literal denotes:
```q
q)2026.09.10 + 14:30:00.000     / date + time
2026.09.10D14:30:00.000000000
q)2026.09.10 + 0D14:30:00       / date + timespan
2026.09.10D14:30:00.000000000
```

The six comparison operators (`<`, `<=`, `=`, `>=`, `>`, `<>`) work on temporal values exactly as they do on numbers, since a temporal value is an integer count under the hood. Restricting a query to a date or time interval is one of the most common operations in q, precisely because q is built for time series

> **Note — Comparing different temporal types**
>
>
> When you compare two different temporal types, q converts one side, and not always in the direction you expect. Comparing a timestamp with a minute truncates the timestamp to a minute, which silently discards seconds. See [comparison of temporal values](../../../ref/comparison.md#temporal-values) for the full conversion matrix.
>
To bound both ends of an interval, prefer [`within`](../../../ref/within.md) over a pair of comparisons. It checks both bounds (inclusive) in a single call, which is faster than evaluating and combining two comparisons, and it reads more directly as a range check:
```q
q)09:31:00.000 within 09:30:00.000 16:00:00.000
1b
```

`within` is equivalent to, but faster than, the same interval expressed as two comparisons.

### Grouping into time buckets with `xbar`

[`xbar`](../../../ref/xbar.md) rounds a temporal value down to the nearest multiple of a fixed interval, which makes it the standard way to group rows into time buckets:
```q
q)time: 09:31:00
q)5 xbar time.minute
09:30
```

`xbar` only produces buckets of equal, fixed width. For custom buckets — such as trading sessions of unequal length — build a [step dictionary](dictionaries.md#step-dictionaries) that maps each bucket's start time to a label, and apply it to the time column.

### Dot notation and casting

Dot notation extracts a component of a temporal value. The type names (`date`, `time`, `minute`, `second`, `month`) return a temporal value of that type; the component names (`year`, `mm`, `dd`, `hh`, `uu`, `ss`) return an `int`:
```q
q)d: 2026.09.10D14:35:27.123456789
q)d.date
2026.09.10
q)d.minute
14:35
q)d.month
2026.09m
q)d.year
2026i
q)d.mm
9i
q)d.hh
14i
```

Casting with [`$`](../../../ref/cast.md) is equivalent for the type-valued components, and is the form to prefer in code because it also works on lists and inside queries:
```q
q)`date$d
2026.09.10
q)`minute$d
14:35
q)`timespan$d       / time of day as a duration
0D14:35:27.123456789
```

### Parsing

To parse a string, pass the uppercase form of the corresponding type character as the left argument to [`$`](../../../ref/tok.md). Dates are tolerant about separators:
```q
q)"D"$ ("20260914"; "2026-09-14"; "2026.09.14"; "2026/09/14")
2026.09.14 2026.09.14 2026.09.14 2026.09.14
```

Times must have the form `HH:MM:SS.mmm`. You can shorten them from the right, as these examples show; q zeroes the numbers you omit:
```q
q)"T"$ ("07:08:09.010"; "07:08:09"; "07:08"; "07")
07:08:09.010 07:08:09.000 07:08:00.000 07:00:00.000
```

`"P"$` accepts separators other than `D` between the date and the time — including the `T` of ISO-8601, so an ISO timestamp parses as it stands:
```q
q)"P"$"2026.09.14T15:34:03.000000000"
2026.09.14D15:34:03.000000000
```

It also reads seconds since the Unix epoch:
```q
q)"P"$"1789400043"     / 2026.09.14 15:34:03 UTC
2026.09.14D15:34:03.000000000
```

Those two forms are ambiguous, and q reads digits alone as Unix seconds. So a compact date that `"D"$` parses as a date is _not_ the same day as `"P"$`:
```q
q)"P"$"20260914"
2000.03.25D10:09:14.000000000
```

[`.h.iso8601`](../../../ref/doth.md#hiso8601-iso-timestamp) goes the other way, returning an ISO-8601 string:
```q
q).h.iso8601 2026.09.14D15:34:03.000000000
"2026-09-14T15:34:03.000000000"
```

The same uppercase rule parses the non-temporal types too — `"J"$` for a `long`, `"F"$` for a `float`, and `"S"$` for a `symbol`. See [Tok](../../../ref/tok.md) for the full set of type characters.

> **Warning — Uppercase parses a string; a type name casts it**
>
>
> [Tok](../../../ref/tok.md) _interprets_ a string when passed an uppercase char (or the negative type number). Type names and lowercase chars are [Cast](../../../ref/cast.md), which converts a _value_ — and a string is a list of chars, so casting converts each character code separately. The result is nonsense rather than an error:
>
> ```q
> q)"D"$"2026.09.14"       / Tok: parses the string
> 2026.09.14
> q)`date$"2026.09.14"     / Cast: one date per character code
> 2000.02.20 2000.02.18 2000.02.20 2000.02.24 2000.02.16 2000.02.18 2000.02.27 ..
> ```
>
Parsing is all-or-nothing, and it never signals an error: anything it cannot read becomes the null of the target type. It also consumes one whole string per value, so a string holding several values has to be split first:
```q
q)"D"$("2026.09.14"; "notadate"; "")
2026.09.14 0N 0N
q)"J"$"1 2 3"           / one string, so one value
0N
q)"J"$" " vs "1 2 3"    / split, then parse each
1 2 3
```

> **Note — `\z` selects the slash date format**
>
>
> A slash-separated date is read as mm/dd/yyyy by default. Use [`-z`](../../../ref/cmdline.md#-z-date-format) on the command line, or [`\z`](../../../ref/syscmds.md#z-date-parsing) in the session, to switch to dd/mm/yyyy (`1`). The other date forms are unaffected.
>
> ```q
> q)"D"$("09/14/2026"; "14/09/2026")
> 2026.09.14 0N
> q)\z 1
> q)"D"$("09/14/2026"; "14/09/2026")
> 0N 2026.09.14
> ```
>
### Time zones

**A time zone is not stored with a temporal value.** A timestamp is just a count of nanoseconds; how you interpret it is a convention you must maintain yourself. The usual practice is to store UTC and convert on display.
```q
q).z.p                              / current UTC timestamp
2026.09.10D12:40:38.048740000
q).z.P                              / current local timestamp
2026.09.10D14:40:38.048795000
q).z.D                              / current local date
2026.09.10
```

Convert between the two with [`gtime` and `ltime`](../../../ref/gtime.md). The offset applied is the one in effect on the machine, so the results below are from a host set to UTC+2:
```q
q)gtime 2026.09.10D14:00:00.000000000   / local to UTC
2026.09.10D12:00:00.000000000
q)ltime 2026.09.10D14:00:00.000000000   / UTC to local
2026.09.10D16:00:00.000000000
```

See [`.z.p`](../../../ref/dotz.md#zp-utc-timestamp), [`.z.P`](../../../ref/dotz.md#zp-local-timestamp), and [`.z.D`](../../../ref/dotz.md#zt-zt-zd-zd-timedate-shortcuts).

### Month arithmetic

Days are a fixed length; months are not. Month arithmetic therefore needs [`.Q.addmonths`](../../../ref/dotq.md#addmonths):


**q**
```q
q).Q.addmonths[2026.09.10; -3]
2026.06.10
```


**Python**
```python
>>> from datetime import date
>>> d = date(2026, 9, 10)
>>> m = d.month - 1 - 3     # zero-based month index
>>> date(d.year + m // 12, m % 12 + 1, d.day)
datetime.date(2026, 6, 10)
```


The standard library has no month unit, only days and smaller, so you have to wrap the year and month by hand.

`.Q.addmonths` does not clamp to the end of the month. If the day of month does not exist in the target month, the result rolls over into the following month:
```q
q).Q.addmonths[2026.01.31; 1]   / 2026.02.31 does not exist
2026.03.03
```

> **Warning — The `datetime` type (`15h`) is deprecated**
>
>
> Use `timestamp` (`12h`) instead. `datetime` stores the time of day as a float fraction of a day, so it cannot represent every millisecond exactly, and equality comparisons on it are unreliable.
>
## GUID

A GUID (globally unique identifier) is a 16-byte value, typically used for transaction and record IDs. Its q type name is `guid`:
```q
q)type 0Ng
-2h
q)1?0Ng             / generate a random guid with Deal
,8c6b8b64-6815-6084-0a3e-178401251b68
q)"G"$"8c680a01-5a49-5aab-5a65-d4bfddb6a661"    / parse from a string
8c680a01-5a49-5aab-5a65-d4bfddb6a661
q)0x0 sv 16?0xff    / build from 16 bytes
5a495aab-5a65-d4bf-ddb6-a66158e53a44
```

[Deal](../../../ref/deal.md) (`?0Ng`) generates globally unique values: it mixes `.z.a`, `.z.i`, and `.z.p`.

`0Ng` is the null guid:
```q
q)0Ng
00000000-0000-0000-0000-000000000000
q)null 0Ng
1b
```

GUIDs have no literal form, and their only conversion is parsing from a string with `"G"$`, as shown above. The only scalar primitives defined on them are `=`, `<`, and `>`, much like symbols.

> **Note — Prefer guid over a char vector for IDs**
>
>
> A guid takes 16 bytes against 40 for the equivalent 16-character string, and comparing two guids with `=` is a single 16-byte comparison rather than a walk over a character list. Use `int`, `symbol`, or `guid` for IDs — not strings.
>
## Null values

Each type reserves one value to mean _missing_. The literal is `0N` followed by the type character; float null is `0n`:
```q
q)(0N; 0Nh; 0Ni; 0Ne; 0n; 0Ng; 0Np; 0Nd)
0N
0Nh
0Ni
0Ne
0n
00000000-0000-0000-0000-000000000000
0Np
0Nd
```

Text nulls are less obvious: the null char is a space and the null symbol is the empty symbol. As stated earlier, `byte` has no null.

Use the [`null`](../../../ref/null.md) keyword rather than comparing against a literal — it is atomic and works across types:
```q
q)null (0N; 0n; `; " "; 0Ng; 0Nd)
111111b
```

Three behaviors are worth internalizing.

**Nulls are contagious in arithmetic.** Any arithmetic involving a null yields a null:
```q
q)0N + 5
0N
q)0n + 5
0n
```

**Aggregations ignore nulls, but `count` does not.** This means `avg` is not `sum % count`:


**q**
```q
q)l: 1 2 0N 4
q)sum l
7
q)avg l         / 7 % 3, not 7 % 4
2.333333
q)count l
4
```


**Python**
```python
>>> import statistics
>>> l = [1, 2, None, 4]
>>> sum(x for x in l if x is not None)
7
>>> statistics.mean(x for x in l if x is not None)
2.3333333333333335
>>> len(l)
4
```


The same holds for weighted aggregations, and there the consequence is subtle: [`wavg`](../../../ref/avg.md#wavg) discards the weight paired with a null, so it is **not** `(sum w * x) % sum w`:
```q
q)w: 1 2 3 4
q)w wavg 1 2 0N 4             / the weight 3 is dropped along with the null
3f
q)1 2 4 wavg 1 2 4            / identical result
3f
q)(sum w * 1 2 0N 4) % sum w  / what the naive formula gives
2.1
```

> **Warning — `med` is the exception**
>
>
> [`med`](../../../ref/med.md) sorts its argument and takes the middle, and because nulls sort first it treats them as values rather than skipping them. Filter them out yourself if that is not what you want.
>
> ```q
> q)med 1 2 0N 4
> 1.5
> q)med {x where not null x} 1 2 0N 4
> 2f
> ```
>
**Nulls sort first and compare below every value**, including negative infinity. Nulls of different types compare equal to each other:
```q
q)asc (5; 0N; 1)
`s#0N 1 5
q)0N < -0W
1b
q)0N = 0Nh
1b
```

To replace nulls, use [`^` Fill and `fills`](../../../ref/fill.md):


**q**
```q
q)0 ^ 0N 5 0N       / replace nulls with 0
0 5 0
q)fills 0N 5 0N 7   / forward-fill
0N 5 5 7
```


**Python**
```python
>>> [0 if x is None else x for x in [None, 5, None]]
[0, 5, 0]
>>> import itertools
>>> ff = lambda a, b: a if b is None else b
>>> list(itertools.accumulate([None, 5, None, 7], ff))
[None, 5, 5, 7]
```


A leading null has nothing to carry forward, so `fills` leaves it in place.

> **Note — Enumerated symbols are the exception**
>
>
> `null` does not detect a null symbol behind an enumeration, because that value is used to indicate _out of range_. See [`null`](../../../ref/null.md) for the workaround.
>
## Infinite values

Each numeric and temporal type also reserves an infinity, written `0W` followed by the type character:
```q
q)(0W; 0Wh; 0Wi; 0w; 0Wp; 0Wd)
0W
0Wh
0Wi
0w
0Wp
0Wd
```

Float infinities follow [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754):
```q
q)1 % 0
0w
q)-1 % 0
-0w
q)0w + 5
0w
q)0w - 0w    / indeterminate, so null
0n
q)0 % 0
0n
```

Integer infinities are **not** special values — they are the largest representable integer, and integer arithmetic does no infinity checks. So arithmetic on them is undefined and wraps around:
```q
q)0W + 1     / wraps onto the null value
0N
q)0Wi + 5i
-2147483644i
```

> **Warning — Treat integer infinities as placeholders only**
>
>
> Use them as sentinels — for example as the open end of a range — but do not perform arithmetic on them. See [Infinities](../../../ref/datatypes.md#infinities) for the details.
>
## Next steps

- Keep the [datatypes reference card](../../../ref/datatypes.md) at hand for type numbers, literals, nulls, and infinities.
- Understand the pitfalls of [float precision](../../../ref/precision.md) and of [comparison](../../../ref/comparison.md) across types.
- Collect atoms of the same type into a [list](lists.md), the core data structure of q.
- Learn more about [handling temporal data](../../../ref/temporal-data.md) in q.
